Standardize usage of virtual/override/final in chrome/browser/ui/
[chromium-blink-merge.git] / chrome / browser / ui / startup / startup_browser_creator.cc
blob295690e2afde26702b72264593bcd70ab0648474
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"
7 #include <algorithm> // For max().
8 #include <set>
10 #include "apps/app_load_service.h"
11 #include "apps/switches.h"
12 #include "base/bind.h"
13 #include "base/bind_helpers.h"
14 #include "base/command_line.h"
15 #include "base/compiler_specific.h"
16 #include "base/environment.h"
17 #include "base/files/file_path.h"
18 #include "base/files/file_util.h"
19 #include "base/lazy_instance.h"
20 #include "base/logging.h"
21 #include "base/memory/scoped_ptr.h"
22 #include "base/metrics/histogram.h"
23 #include "base/metrics/statistics_recorder.h"
24 #include "base/path_service.h"
25 #include "base/prefs/pref_service.h"
26 #include "base/strings/string_number_conversions.h"
27 #include "base/strings/string_split.h"
28 #include "base/strings/utf_string_conversions.h"
29 #include "base/threading/thread_restrictions.h"
30 #include "chrome/browser/app_mode/app_mode_utils.h"
31 #include "chrome/browser/auto_launch_trial.h"
32 #include "chrome/browser/browser_process.h"
33 #include "chrome/browser/chrome_notification_types.h"
34 #include "chrome/browser/custom_handlers/protocol_handler_registry.h"
35 #include "chrome/browser/extensions/startup_helper.h"
36 #include "chrome/browser/extensions/unpacked_installer.h"
37 #include "chrome/browser/first_run/first_run.h"
38 #include "chrome/browser/notifications/desktop_notification_service.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_manager.h"
43 #include "chrome/browser/profiles/profiles_state.h"
44 #include "chrome/browser/search_engines/template_url_service_factory.h"
45 #include "chrome/browser/ui/app_list/app_list_service.h"
46 #include "chrome/browser/ui/browser.h"
47 #include "chrome/browser/ui/browser_dialogs.h"
48 #include "chrome/browser/ui/browser_finder.h"
49 #include "chrome/browser/ui/browser_window.h"
50 #include "chrome/browser/ui/startup/startup_browser_creator_impl.h"
51 #include "chrome/browser/ui/user_manager.h"
52 #include "chrome/common/chrome_constants.h"
53 #include "chrome/common/chrome_paths.h"
54 #include "chrome/common/chrome_result_codes.h"
55 #include "chrome/common/chrome_switches.h"
56 #include "chrome/common/chrome_version_info.h"
57 #include "chrome/common/pref_names.h"
58 #include "chrome/common/url_constants.h"
59 #include "chrome/installer/util/browser_distribution.h"
60 #include "components/google/core/browser/google_util.h"
61 #include "components/search_engines/util.h"
62 #include "components/signin/core/common/profile_management_switches.h"
63 #include "components/url_fixer/url_fixer.h"
64 #include "content/public/browser/browser_thread.h"
65 #include "content/public/browser/child_process_security_policy.h"
66 #include "content/public/browser/navigation_controller.h"
67 #include "net/base/net_util.h"
69 #if defined(USE_ASH)
70 #include "ash/shell.h"
71 #endif
73 #if defined(OS_CHROMEOS)
74 #include "chrome/browser/chromeos/app_mode/app_launch_utils.h"
75 #include "chrome/browser/chromeos/kiosk_mode/kiosk_mode_settings.h"
76 #include "chrome/browser/chromeos/login/demo_mode/demo_app_launcher.h"
77 #include "chrome/browser/chromeos/profiles/profile_helper.h"
78 #include "chrome/browser/lifetime/application_lifetime.h"
79 #include "chromeos/chromeos_switches.h"
80 #include "components/user_manager/user_manager.h"
81 #endif
83 #if defined(TOOLKIT_VIEWS) && defined(OS_LINUX)
84 #include "ui/events/x/touch_factory_x11.h"
85 #endif
87 #if defined(OS_MACOSX)
88 #include "chrome/browser/web_applications/web_app_mac.h"
89 #endif
91 #if defined(ENABLE_FULL_PRINTING)
92 #include "chrome/browser/printing/cloud_print/cloud_print_proxy_service.h"
93 #include "chrome/browser/printing/cloud_print/cloud_print_proxy_service_factory.h"
94 #include "chrome/browser/printing/print_dialog_cloud.h"
95 #endif
97 using content::BrowserThread;
98 using content::ChildProcessSecurityPolicy;
100 namespace {
102 // Keeps track on which profiles have been launched.
103 class ProfileLaunchObserver : public content::NotificationObserver {
104 public:
105 ProfileLaunchObserver()
106 : profile_to_activate_(NULL),
107 activated_profile_(false) {
108 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
109 content::NotificationService::AllSources());
110 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_WINDOW_READY,
111 content::NotificationService::AllSources());
113 ~ProfileLaunchObserver() override {}
115 void Observe(int type,
116 const content::NotificationSource& source,
117 const content::NotificationDetails& details) override {
118 switch (type) {
119 case chrome::NOTIFICATION_PROFILE_DESTROYED: {
120 Profile* profile = content::Source<Profile>(source).ptr();
121 launched_profiles_.erase(profile);
122 opened_profiles_.erase(profile);
123 if (profile == profile_to_activate_)
124 profile_to_activate_ = NULL;
125 // If this profile was the last launched one without an opened window,
126 // then we may be ready to activate |profile_to_activate_|.
127 MaybeActivateProfile();
128 break;
130 case chrome::NOTIFICATION_BROWSER_WINDOW_READY: {
131 Browser* browser = content::Source<Browser>(source).ptr();
132 DCHECK(browser);
133 opened_profiles_.insert(browser->profile());
134 MaybeActivateProfile();
135 break;
137 default:
138 NOTREACHED();
142 bool HasBeenLaunched(const Profile* profile) const {
143 return launched_profiles_.find(profile) != launched_profiles_.end();
146 void AddLaunched(Profile* profile) {
147 launched_profiles_.insert(profile);
148 // Since the startup code only executes for browsers launched in
149 // desktop mode, i.e., HOST_DESKTOP_TYPE_NATIVE. Ash should never get here.
150 if (chrome::FindBrowserWithProfile(profile,
151 chrome::HOST_DESKTOP_TYPE_NATIVE)) {
152 // A browser may get opened before we get initialized (e.g., in tests),
153 // so we never see the NOTIFICATION_BROWSER_WINDOW_READY for it.
154 opened_profiles_.insert(profile);
158 void Clear() {
159 launched_profiles_.clear();
160 opened_profiles_.clear();
163 bool activated_profile() { return activated_profile_; }
165 void set_profile_to_activate(Profile* profile) {
166 profile_to_activate_ = profile;
167 MaybeActivateProfile();
170 private:
171 void MaybeActivateProfile() {
172 if (!profile_to_activate_)
173 return;
174 // Check that browsers have been opened for all the launched profiles.
175 // Note that browsers opened for profiles that were not added as launched
176 // profiles are simply ignored.
177 std::set<const Profile*>::const_iterator i = launched_profiles_.begin();
178 for (; i != launched_profiles_.end(); ++i) {
179 if (opened_profiles_.find(*i) == opened_profiles_.end())
180 return;
182 // Asynchronous post to give a chance to the last window to completely
183 // open and activate before trying to activate |profile_to_activate_|.
184 BrowserThread::PostTask(
185 BrowserThread::UI, FROM_HERE,
186 base::Bind(&ProfileLaunchObserver::ActivateProfile,
187 base::Unretained(this)));
188 // Avoid posting more than once before ActivateProfile gets called.
189 registrar_.Remove(this, chrome::NOTIFICATION_BROWSER_WINDOW_READY,
190 content::NotificationService::AllSources());
191 registrar_.Remove(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
192 content::NotificationService::AllSources());
195 void ActivateProfile() {
196 // We need to test again, in case the profile got deleted in the mean time.
197 if (profile_to_activate_) {
198 Browser* browser = chrome::FindBrowserWithProfile(
199 profile_to_activate_, chrome::HOST_DESKTOP_TYPE_NATIVE);
200 // |profile| may never get launched, e.g., if it only had
201 // incognito Windows and one of them was used to exit Chrome.
202 // So it won't have a browser in that case.
203 if (browser)
204 browser->window()->Activate();
205 // No need try to activate this profile again.
206 profile_to_activate_ = NULL;
208 // Assign true here, even if no browser was actually activated, so that
209 // the test can stop waiting, and fail gracefully when needed.
210 activated_profile_ = true;
213 // These are the profiles that get launched by
214 // StartupBrowserCreator::LaunchBrowser.
215 std::set<const Profile*> launched_profiles_;
216 // These are the profiles for which at least one browser window has been
217 // opened. This is needed to know when it is safe to activate
218 // |profile_to_activate_|, otherwise, new browser windows being opened will
219 // be activated on top of it.
220 std::set<const Profile*> opened_profiles_;
221 content::NotificationRegistrar registrar_;
222 // This is NULL until the profile to activate has been chosen. This value,
223 // should only be set once all profiles have been launched, otherwise,
224 // activation may not happen after the launch of newer profiles.
225 Profile* profile_to_activate_;
226 // Set once we attempted to activate a profile. We only get one shot at this.
227 bool activated_profile_;
229 DISALLOW_COPY_AND_ASSIGN(ProfileLaunchObserver);
232 base::LazyInstance<ProfileLaunchObserver> profile_launch_observer =
233 LAZY_INSTANCE_INITIALIZER;
235 // Dumps the current set of the browser process's histograms to |output_file|.
236 // The file is overwritten if it exists. This function should only be called in
237 // the blocking pool.
238 void DumpBrowserHistograms(const base::FilePath& output_file) {
239 base::ThreadRestrictions::AssertIOAllowed();
241 std::string output_string(base::StatisticsRecorder::ToJSON(std::string()));
242 base::WriteFile(output_file, output_string.data(),
243 static_cast<int>(output_string.size()));
246 } // namespace
248 StartupBrowserCreator::StartupBrowserCreator()
249 : is_default_browser_dialog_suppressed_(false),
250 show_main_browser_window_(true) {
253 StartupBrowserCreator::~StartupBrowserCreator() {}
255 // static
256 bool StartupBrowserCreator::was_restarted_read_ = false;
258 // static
259 bool StartupBrowserCreator::in_synchronous_profile_launch_ = false;
261 void StartupBrowserCreator::AddFirstRunTab(const GURL& url) {
262 first_run_tabs_.push_back(url);
265 // static
266 bool StartupBrowserCreator::InSynchronousProfileLaunch() {
267 return in_synchronous_profile_launch_;
270 bool StartupBrowserCreator::LaunchBrowser(
271 const CommandLine& command_line,
272 Profile* profile,
273 const base::FilePath& cur_dir,
274 chrome::startup::IsProcessStartup process_startup,
275 chrome::startup::IsFirstRun is_first_run,
276 int* return_code) {
278 in_synchronous_profile_launch_ =
279 process_startup == chrome::startup::IS_PROCESS_STARTUP;
280 DCHECK(profile);
282 // Continue with the incognito profile from here on if Incognito mode
283 // is forced.
284 if (IncognitoModePrefs::ShouldLaunchIncognito(command_line,
285 profile->GetPrefs())) {
286 profile = profile->GetOffTheRecordProfile();
287 } else if (command_line.HasSwitch(switches::kIncognito)) {
288 LOG(WARNING) << "Incognito mode disabled by policy, launching a normal "
289 << "browser session.";
292 // Note: This check should have been done in ProcessCmdLineImpl()
293 // before calling this function. However chromeos/login/login_utils.cc
294 // calls this function directly (see comments there) so it has to be checked
295 // again.
296 const bool silent_launch = command_line.HasSwitch(switches::kSilentLaunch);
298 if (!silent_launch) {
299 StartupBrowserCreatorImpl lwp(cur_dir, command_line, this, is_first_run);
300 const std::vector<GURL> urls_to_launch =
301 GetURLsFromCommandLine(command_line, cur_dir, profile);
302 chrome::HostDesktopType host_desktop_type =
303 chrome::HOST_DESKTOP_TYPE_NATIVE;
305 #if defined(USE_ASH) && !defined(OS_CHROMEOS)
306 // We want to maintain only one type of instance for now, either ASH
307 // or desktop.
308 // TODO(shrikant): Remove this code once we decide on running both desktop
309 // and ASH instances side by side.
310 if (ash::Shell::HasInstance())
311 host_desktop_type = chrome::HOST_DESKTOP_TYPE_ASH;
312 #endif
314 const bool launched = lwp.Launch(profile, urls_to_launch,
315 in_synchronous_profile_launch_,
316 host_desktop_type);
317 in_synchronous_profile_launch_ = false;
318 if (!launched) {
319 LOG(ERROR) << "launch error";
320 if (return_code)
321 *return_code = chrome::RESULT_CODE_INVALID_CMDLINE_URL;
322 return false;
324 } else {
325 in_synchronous_profile_launch_ = false;
328 profile_launch_observer.Get().AddLaunched(profile);
330 #if defined(OS_CHROMEOS)
331 chromeos::ProfileHelper::Get()->ProfileStartup(profile, process_startup);
332 #endif
333 return true;
336 // static
337 bool StartupBrowserCreator::WasRestarted() {
338 // Stores the value of the preference kWasRestarted had when it was read.
339 static bool was_restarted = false;
341 if (!was_restarted_read_) {
342 PrefService* pref_service = g_browser_process->local_state();
343 was_restarted = pref_service->GetBoolean(prefs::kWasRestarted);
344 pref_service->SetBoolean(prefs::kWasRestarted, false);
345 was_restarted_read_ = true;
347 return was_restarted;
350 // static
351 SessionStartupPref StartupBrowserCreator::GetSessionStartupPref(
352 const CommandLine& command_line,
353 Profile* profile) {
354 DCHECK(profile);
355 PrefService* prefs = profile->GetPrefs();
356 SessionStartupPref pref = SessionStartupPref::GetStartupPref(prefs);
358 // IsChromeFirstRun() looks for a sentinel file to determine whether the user
359 // is starting Chrome for the first time. On Chrome OS, the sentinel is stored
360 // in a location shared by all users and the check is meaningless. Query the
361 // UserManager instead to determine whether the user is new.
362 #if defined(OS_CHROMEOS)
363 const bool is_first_run =
364 user_manager::UserManager::Get()->IsCurrentUserNew();
365 // On ChromeOS restarts force the user to login again. The expectation is that
366 // after a login the user gets clean state. For this reason we ignore
367 // StartupBrowserCreator::WasRestarted().
368 const bool did_restart = false;
369 #else
370 const bool is_first_run = first_run::IsChromeFirstRun();
371 const bool did_restart = StartupBrowserCreator::WasRestarted();
372 #endif
374 // The pref has an OS-dependent default value. For the first run only, this
375 // default is overridden with SessionStartupPref::DEFAULT so that first run
376 // behavior (sync promo, welcome page) is consistently invoked.
377 // This applies only if the pref is still at its default and has not been
378 // set by the user, managed prefs or policy.
379 if (is_first_run && SessionStartupPref::TypeIsDefault(prefs))
380 pref.type = SessionStartupPref::DEFAULT;
382 // The switches::kRestoreLastSession command line switch is used to restore
383 // sessions after a browser self restart (e.g. after a Chrome upgrade).
384 // However, new profiles can be created from a browser process that has this
385 // switch so do not set the session pref to SessionStartupPref::LAST for
386 // those as there is nothing to restore.
387 if ((command_line.HasSwitch(switches::kRestoreLastSession) || did_restart) &&
388 !profile->IsNewProfile()) {
389 pref.type = SessionStartupPref::LAST;
391 if (pref.type == SessionStartupPref::LAST &&
392 IncognitoModePrefs::ShouldLaunchIncognito(command_line, prefs)) {
393 // We don't store session information when incognito. If the user has
394 // chosen to restore last session and launched incognito, fallback to
395 // default launch behavior.
396 pref.type = SessionStartupPref::DEFAULT;
399 return pref;
402 // static
403 void StartupBrowserCreator::ClearLaunchedProfilesForTesting() {
404 profile_launch_observer.Get().Clear();
407 // static
408 std::vector<GURL> StartupBrowserCreator::GetURLsFromCommandLine(
409 const CommandLine& command_line,
410 const base::FilePath& cur_dir,
411 Profile* profile) {
412 std::vector<GURL> urls;
414 const CommandLine::StringVector& params = command_line.GetArgs();
415 for (size_t i = 0; i < params.size(); ++i) {
416 base::FilePath param = base::FilePath(params[i]);
417 // Handle Vista way of searching - "? <search-term>"
418 if ((param.value().size() > 2) && (param.value()[0] == '?') &&
419 (param.value()[1] == ' ')) {
420 GURL url(GetDefaultSearchURLForSearchTerms(
421 TemplateURLServiceFactory::GetForProfile(profile),
422 param.LossyDisplayName().substr(2)));
423 if (url.is_valid()) {
424 urls.push_back(url);
425 continue;
429 // Otherwise, fall through to treating it as a URL.
431 // This will create a file URL or a regular URL.
432 // This call can (in rare circumstances) block the UI thread.
433 // Allow it until this bug is fixed.
434 // http://code.google.com/p/chromium/issues/detail?id=60641
435 GURL url = GURL(param.MaybeAsASCII());
436 // http://crbug.com/371030: Only use URLFixerUpper if we don't have a valid
437 // URL, otherwise we will look in the current directory for a file named
438 // 'about' if the browser was started with a about:foo argument.
439 if (!url.is_valid()) {
440 base::ThreadRestrictions::ScopedAllowIO allow_io;
441 url = url_fixer::FixupRelativeFile(cur_dir, param);
443 // Exclude dangerous schemes.
444 if (url.is_valid()) {
445 ChildProcessSecurityPolicy* policy =
446 ChildProcessSecurityPolicy::GetInstance();
447 if (policy->IsWebSafeScheme(url.scheme()) ||
448 url.SchemeIs(url::kFileScheme) ||
449 #if defined(OS_CHROMEOS)
450 // In ChromeOS, allow any settings page to be specified on the command
451 // line. See ExistingUserController::OnLoginSuccess.
452 (url.spec().find(chrome::kChromeUISettingsURL) == 0) ||
453 #else
454 ((url.spec().find(std::string(chrome::kChromeUISettingsURL) +
455 chrome::kResetProfileSettingsSubPage) == 0)) ||
456 #endif
457 (url.spec().compare(url::kAboutBlankURL) == 0)) {
458 urls.push_back(url);
462 return urls;
465 // static
466 bool StartupBrowserCreator::ProcessCmdLineImpl(
467 const CommandLine& command_line,
468 const base::FilePath& cur_dir,
469 bool process_startup,
470 Profile* last_used_profile,
471 const Profiles& last_opened_profiles,
472 int* return_code,
473 StartupBrowserCreator* browser_creator) {
474 DCHECK(last_used_profile);
475 if (process_startup) {
476 if (command_line.HasSwitch(switches::kDisablePromptOnRepost))
477 content::NavigationController::DisablePromptOnRepost();
480 bool silent_launch = false;
482 #if defined(ENABLE_FULL_PRINTING)
483 // If we are just displaying a print dialog we shouldn't open browser
484 // windows.
485 if (command_line.HasSwitch(switches::kCloudPrintFile) &&
486 print_dialog_cloud::CreatePrintDialogFromCommandLine(last_used_profile,
487 command_line)) {
488 silent_launch = true;
491 // If we are checking the proxy enabled policy, don't open any windows.
492 if (command_line.HasSwitch(switches::kCheckCloudPrintConnectorPolicy)) {
493 silent_launch = true;
494 if (CloudPrintProxyServiceFactory::GetForProfile(last_used_profile)->
495 EnforceCloudPrintConnectorPolicyAndQuit())
496 // Success, nothing more needs to be done, so return false to stop
497 // launching and quit.
498 return false;
500 #endif // defined(ENABLE_FULL_PRINTING)
502 if (command_line.HasSwitch(switches::kExplicitlyAllowedPorts)) {
503 std::string allowed_ports =
504 command_line.GetSwitchValueASCII(switches::kExplicitlyAllowedPorts);
505 net::SetExplicitlyAllowedPorts(allowed_ports);
508 if (command_line.HasSwitch(switches::kInstallEphemeralAppFromWebstore)) {
509 extensions::StartupHelper helper;
510 helper.InstallEphemeralApp(command_line, last_used_profile);
511 // Nothing more needs to be done, so return false to stop launching and
512 // quit.
513 return false;
516 if (command_line.HasSwitch(switches::kValidateCrx)) {
517 if (!process_startup) {
518 LOG(ERROR) << "chrome is already running; you must close all running "
519 << "instances before running with the --"
520 << switches::kValidateCrx << " flag";
521 return false;
523 extensions::StartupHelper helper;
524 std::string message;
525 std::string error;
526 if (helper.ValidateCrx(command_line, &error))
527 message = std::string("ValidateCrx Success");
528 else
529 message = std::string("ValidateCrx Failure: ") + error;
530 printf("%s\n", message.c_str());
531 return false;
534 #if defined(OS_CHROMEOS)
536 #if defined(USE_ATHENA)
537 // Athena will never launch browser.
538 silent_launch = true;
539 #endif
541 // The browser will be launched after the user logs in.
542 if (command_line.HasSwitch(chromeos::switches::kLoginManager))
543 silent_launch = true;
545 if (chrome::IsRunningInAppMode() &&
546 command_line.HasSwitch(switches::kAppId)) {
547 chromeos::LaunchAppOrDie(
548 last_used_profile,
549 command_line.GetSwitchValueASCII(switches::kAppId));
551 // Skip browser launch since app mode launches its app window.
552 silent_launch = true;
555 // If we are a demo app session and we crashed, there is no safe recovery
556 // possible. We should instead cleanly exit and go back to the OOBE screen,
557 // where we will launch again after the timeout has expired.
558 if (chromeos::DemoAppLauncher::IsDemoAppSession(
559 command_line.GetSwitchValueASCII(chromeos::switches::kLoginUser))) {
560 chrome::AttemptUserExit();
561 return false;
563 #endif // OS_CHROMEOS
565 #if defined(TOOLKIT_VIEWS) && defined(USE_X11)
566 ui::TouchFactory::SetTouchDeviceListFromCommandLine();
567 #endif
569 #if defined(OS_MACOSX)
570 if (web_app::MaybeRebuildShortcut(command_line))
571 return true;
572 #endif
574 if (!process_startup &&
575 command_line.HasSwitch(switches::kDumpBrowserHistograms)) {
576 // Only handle --dump-browser-histograms from a rendezvous. In this case, do
577 // not open a new browser window even if no output file was given.
578 base::FilePath output_file(
579 command_line.GetSwitchValuePath(switches::kDumpBrowserHistograms));
580 if (!output_file.empty()) {
581 BrowserThread::PostBlockingPoolTask(
582 FROM_HERE,
583 base::Bind(&DumpBrowserHistograms, output_file));
585 silent_launch = true;
588 // If we don't want to launch a new browser window or tab we are done here.
589 if (silent_launch)
590 return true;
592 // Check for --load-and-launch-app.
593 if (command_line.HasSwitch(apps::kLoadAndLaunchApp) &&
594 !IncognitoModePrefs::ShouldLaunchIncognito(
595 command_line, last_used_profile->GetPrefs())) {
596 CommandLine::StringType path = command_line.GetSwitchValueNative(
597 apps::kLoadAndLaunchApp);
599 if (!apps::AppLoadService::Get(last_used_profile)->LoadAndLaunch(
600 base::FilePath(path), command_line, cur_dir)) {
601 return false;
604 // Return early here since we don't want to open a browser window.
605 // The exception is when there are no browser windows, since we don't want
606 // chrome to shut down.
607 // TODO(jackhou): Do this properly once keep-alive is handled by the
608 // background page of apps. Tracked at http://crbug.com/175381
609 if (chrome::GetTotalBrowserCountForProfile(last_used_profile) != 0)
610 return true;
613 chrome::startup::IsProcessStartup is_process_startup = process_startup ?
614 chrome::startup::IS_PROCESS_STARTUP :
615 chrome::startup::IS_NOT_PROCESS_STARTUP;
616 chrome::startup::IsFirstRun is_first_run = first_run::IsChromeFirstRun() ?
617 chrome::startup::IS_FIRST_RUN : chrome::startup::IS_NOT_FIRST_RUN;
618 // |last_opened_profiles| will be empty in the following circumstances:
619 // - This is the first launch. |last_used_profile| is the initial profile.
620 // - The user exited the browser by closing all windows for all
621 // profiles. |last_used_profile| is the profile which owned the last open
622 // window.
623 // - Only incognito windows were open when the browser exited.
624 // |last_used_profile| is the last used incognito profile. Restoring it will
625 // create a browser window for the corresponding original profile.
626 if (last_opened_profiles.empty()) {
627 // If the last used profile is locked or was a guest, show the user manager.
628 if (switches::IsNewAvatarMenu()) {
629 ProfileInfoCache& profile_info =
630 g_browser_process->profile_manager()->GetProfileInfoCache();
631 size_t profile_index = profile_info.GetIndexOfProfileWithPath(
632 last_used_profile->GetPath());
633 bool signin_required = profile_index != std::string::npos &&
634 profile_info.ProfileIsSigninRequiredAtIndex(profile_index);
636 // Guest or locked profiles cannot be re-opened on startup.
637 if (signin_required || last_used_profile->IsGuestSession()) {
638 UserManager::Show(base::FilePath(),
639 profiles::USER_MANAGER_NO_TUTORIAL,
640 profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION);
641 return true;
644 if (!browser_creator->LaunchBrowser(command_line, last_used_profile,
645 cur_dir, is_process_startup,
646 is_first_run, return_code)) {
647 return false;
649 } else {
650 // Guest profiles should not be reopened on startup. This can happen if
651 // the last used profile was a Guest, but other profiles were also open
652 // when Chrome was closed. In this case, pick a different open profile
653 // to be the active one, since the Guest profile is never added to the list
654 // of open profiles.
655 if (switches::IsNewAvatarMenu() && last_used_profile->IsGuestSession()) {
656 DCHECK(!last_opened_profiles[0]->IsGuestSession());
657 last_used_profile = last_opened_profiles[0];
660 // Launch the last used profile with the full command line, and the other
661 // opened profiles without the URLs to launch.
662 CommandLine command_line_without_urls(command_line.GetProgram());
663 const CommandLine::SwitchMap& switches = command_line.GetSwitches();
664 for (CommandLine::SwitchMap::const_iterator switch_it = switches.begin();
665 switch_it != switches.end(); ++switch_it) {
666 command_line_without_urls.AppendSwitchNative(switch_it->first,
667 switch_it->second);
669 // Launch the profiles in the order they became active.
670 for (Profiles::const_iterator it = last_opened_profiles.begin();
671 it != last_opened_profiles.end(); ++it) {
672 DCHECK(!(*it)->IsGuestSession());
673 // Don't launch additional profiles which would only open a new tab
674 // page. When restarting after an update, all profiles will reopen last
675 // open pages.
676 SessionStartupPref startup_pref =
677 GetSessionStartupPref(command_line, *it);
678 if (*it != last_used_profile &&
679 startup_pref.type == SessionStartupPref::DEFAULT &&
680 !HasPendingUncleanExit(*it))
681 continue;
683 if (!browser_creator->LaunchBrowser((*it == last_used_profile) ?
684 command_line : command_line_without_urls, *it, cur_dir,
685 is_process_startup, is_first_run, return_code))
686 return false;
687 // We've launched at least one browser.
688 is_process_startup = chrome::startup::IS_NOT_PROCESS_STARTUP;
690 // This must be done after all profiles have been launched so the observer
691 // knows about all profiles to wait for before activating this one.
692 profile_launch_observer.Get().set_profile_to_activate(last_used_profile);
694 return true;
697 // static
698 void StartupBrowserCreator::ProcessCommandLineOnProfileCreated(
699 const CommandLine& command_line,
700 const base::FilePath& cur_dir,
701 Profile* profile,
702 Profile::CreateStatus status) {
703 if (status == Profile::CREATE_STATUS_INITIALIZED)
704 ProcessCmdLineImpl(command_line, cur_dir, false, profile, Profiles(), NULL,
705 NULL);
708 // static
709 void StartupBrowserCreator::ProcessCommandLineAlreadyRunning(
710 const CommandLine& command_line,
711 const base::FilePath& cur_dir,
712 const base::FilePath& profile_path) {
713 ProfileManager* profile_manager = g_browser_process->profile_manager();
714 Profile* profile = profile_manager->GetProfileByPath(profile_path);
716 // The profile isn't loaded yet and so needs to be loaded asynchronously.
717 if (!profile) {
718 profile_manager->CreateProfileAsync(profile_path,
719 base::Bind(&StartupBrowserCreator::ProcessCommandLineOnProfileCreated,
720 command_line, cur_dir), base::string16(), base::string16(),
721 std::string());
722 return;
725 ProcessCmdLineImpl(command_line, cur_dir, false, profile, Profiles(), NULL,
726 NULL);
729 // static
730 bool StartupBrowserCreator::ActivatedProfile() {
731 return profile_launch_observer.Get().activated_profile();
734 bool HasPendingUncleanExit(Profile* profile) {
735 return profile->GetLastSessionExitType() == Profile::EXIT_CRASHED &&
736 !profile_launch_observer.Get().HasBeenLaunched(profile);
739 base::FilePath GetStartupProfilePath(const base::FilePath& user_data_dir,
740 const CommandLine& command_line) {
741 if (command_line.HasSwitch(switches::kProfileDirectory)) {
742 return user_data_dir.Append(
743 command_line.GetSwitchValuePath(switches::kProfileDirectory));
746 // If we are showing the app list then chrome isn't shown so load the app
747 // list's profile rather than chrome's.
748 if (command_line.HasSwitch(switches::kShowAppList)) {
749 return AppListService::Get(chrome::HOST_DESKTOP_TYPE_NATIVE)->
750 GetProfilePath(user_data_dir);
753 return g_browser_process->profile_manager()->GetLastUsedProfileDir(
754 user_data_dir);