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().
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/file_util.h"
18 #include "base/files/file_path.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/google/google_util.h"
39 #include "chrome/browser/notifications/desktop_notification_service.h"
40 #include "chrome/browser/prefs/incognito_mode_prefs.h"
41 #include "chrome/browser/prefs/session_startup_pref.h"
42 #include "chrome/browser/profiles/profile.h"
43 #include "chrome/browser/profiles/profile_manager.h"
44 #include "chrome/browser/profiles/profiles_state.h"
45 #include "chrome/browser/search_engines/util.h"
46 #include "chrome/browser/ui/app_list/app_list_service.h"
47 #include "chrome/browser/ui/browser.h"
48 #include "chrome/browser/ui/browser_dialogs.h"
49 #include "chrome/browser/ui/browser_finder.h"
50 #include "chrome/browser/ui/browser_window.h"
51 #include "chrome/browser/ui/startup/startup_browser_creator_impl.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/net/url_fixer_upper.h"
58 #include "chrome/common/pref_names.h"
59 #include "chrome/common/url_constants.h"
60 #include "chrome/installer/util/browser_distribution.h"
61 #include "components/signin/core/common/profile_management_switches.h"
62 #include "content/public/browser/browser_thread.h"
63 #include "content/public/browser/child_process_security_policy.h"
64 #include "content/public/browser/navigation_controller.h"
65 #include "grit/locale_settings.h"
66 #include "net/base/net_util.h"
67 #include "ui/base/l10n/l10n_util.h"
68 #include "ui/base/resource/resource_bundle.h"
71 #include "ash/shell.h"
74 #if defined(OS_CHROMEOS)
75 #include "chrome/browser/chromeos/app_mode/app_launch_utils.h"
76 #include "chrome/browser/chromeos/kiosk_mode/kiosk_mode_settings.h"
77 #include "chrome/browser/chromeos/login/demo_mode/demo_app_launcher.h"
78 #include "chrome/browser/chromeos/login/user_manager.h"
79 #include "chrome/browser/chromeos/profiles/profile_helper.h"
80 #include "chrome/browser/lifetime/application_lifetime.h"
81 #include "chromeos/chromeos_switches.h"
84 #if defined(TOOLKIT_VIEWS) && defined(OS_LINUX)
85 #include "ui/events/x/touch_factory_x11.h"
88 #if defined(ENABLE_FULL_PRINTING)
89 #include "chrome/browser/printing/cloud_print/cloud_print_proxy_service.h"
90 #include "chrome/browser/printing/cloud_print/cloud_print_proxy_service_factory.h"
91 #include "chrome/browser/printing/print_dialog_cloud.h"
94 using content::BrowserThread
;
95 using content::ChildProcessSecurityPolicy
;
99 // Keeps track on which profiles have been launched.
100 class ProfileLaunchObserver
: public content::NotificationObserver
{
102 ProfileLaunchObserver()
103 : profile_to_activate_(NULL
),
104 activated_profile_(false) {
105 registrar_
.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED
,
106 content::NotificationService::AllSources());
107 registrar_
.Add(this, chrome::NOTIFICATION_BROWSER_WINDOW_READY
,
108 content::NotificationService::AllSources());
110 virtual ~ProfileLaunchObserver() {}
112 virtual void Observe(int type
,
113 const content::NotificationSource
& source
,
114 const content::NotificationDetails
& details
) OVERRIDE
{
116 case chrome::NOTIFICATION_PROFILE_DESTROYED
: {
117 Profile
* profile
= content::Source
<Profile
>(source
).ptr();
118 launched_profiles_
.erase(profile
);
119 opened_profiles_
.erase(profile
);
120 if (profile
== profile_to_activate_
)
121 profile_to_activate_
= NULL
;
122 // If this profile was the last launched one without an opened window,
123 // then we may be ready to activate |profile_to_activate_|.
124 MaybeActivateProfile();
127 case chrome::NOTIFICATION_BROWSER_WINDOW_READY
: {
128 Browser
* browser
= content::Source
<Browser
>(source
).ptr();
130 opened_profiles_
.insert(browser
->profile());
131 MaybeActivateProfile();
139 bool HasBeenLaunched(const Profile
* profile
) const {
140 return launched_profiles_
.find(profile
) != launched_profiles_
.end();
143 void AddLaunched(Profile
* profile
) {
144 launched_profiles_
.insert(profile
);
145 // Since the startup code only executes for browsers launched in
146 // desktop mode, i.e., HOST_DESKTOP_TYPE_NATIVE. Ash should never get here.
147 if (chrome::FindBrowserWithProfile(profile
,
148 chrome::HOST_DESKTOP_TYPE_NATIVE
)) {
149 // A browser may get opened before we get initialized (e.g., in tests),
150 // so we never see the NOTIFICATION_BROWSER_WINDOW_READY for it.
151 opened_profiles_
.insert(profile
);
156 launched_profiles_
.clear();
157 opened_profiles_
.clear();
160 bool activated_profile() { return activated_profile_
; }
162 void set_profile_to_activate(Profile
* profile
) {
163 profile_to_activate_
= profile
;
164 MaybeActivateProfile();
168 void MaybeActivateProfile() {
169 if (!profile_to_activate_
)
171 // Check that browsers have been opened for all the launched profiles.
172 // Note that browsers opened for profiles that were not added as launched
173 // profiles are simply ignored.
174 std::set
<const Profile
*>::const_iterator i
= launched_profiles_
.begin();
175 for (; i
!= launched_profiles_
.end(); ++i
) {
176 if (opened_profiles_
.find(*i
) == opened_profiles_
.end())
179 // Asynchronous post to give a chance to the last window to completely
180 // open and activate before trying to activate |profile_to_activate_|.
181 BrowserThread::PostTask(
182 BrowserThread::UI
, FROM_HERE
,
183 base::Bind(&ProfileLaunchObserver::ActivateProfile
,
184 base::Unretained(this)));
185 // Avoid posting more than once before ActivateProfile gets called.
186 registrar_
.Remove(this, chrome::NOTIFICATION_BROWSER_WINDOW_READY
,
187 content::NotificationService::AllSources());
188 registrar_
.Remove(this, chrome::NOTIFICATION_PROFILE_DESTROYED
,
189 content::NotificationService::AllSources());
192 void ActivateProfile() {
193 // We need to test again, in case the profile got deleted in the mean time.
194 if (profile_to_activate_
) {
195 Browser
* browser
= chrome::FindBrowserWithProfile(
196 profile_to_activate_
, chrome::HOST_DESKTOP_TYPE_NATIVE
);
197 // |profile| may never get launched, e.g., if it only had
198 // incognito Windows and one of them was used to exit Chrome.
199 // So it won't have a browser in that case.
201 browser
->window()->Activate();
202 // No need try to activate this profile again.
203 profile_to_activate_
= NULL
;
205 // Assign true here, even if no browser was actually activated, so that
206 // the test can stop waiting, and fail gracefully when needed.
207 activated_profile_
= true;
210 // These are the profiles that get launched by
211 // StartupBrowserCreator::LaunchBrowser.
212 std::set
<const Profile
*> launched_profiles_
;
213 // These are the profiles for which at least one browser window has been
214 // opened. This is needed to know when it is safe to activate
215 // |profile_to_activate_|, otherwise, new browser windows being opened will
216 // be activated on top of it.
217 std::set
<const Profile
*> opened_profiles_
;
218 content::NotificationRegistrar registrar_
;
219 // This is NULL until the profile to activate has been chosen. This value,
220 // should only be set once all profiles have been launched, otherwise,
221 // activation may not happen after the launch of newer profiles.
222 Profile
* profile_to_activate_
;
223 // Set once we attempted to activate a profile. We only get one shot at this.
224 bool activated_profile_
;
226 DISALLOW_COPY_AND_ASSIGN(ProfileLaunchObserver
);
229 base::LazyInstance
<ProfileLaunchObserver
> profile_launch_observer
=
230 LAZY_INSTANCE_INITIALIZER
;
232 // Dumps the current set of the browser process's histograms to |output_file|.
233 // The file is overwritten if it exists. This function should only be called in
234 // the blocking pool.
235 void DumpBrowserHistograms(const base::FilePath
& output_file
) {
236 base::ThreadRestrictions::AssertIOAllowed();
238 std::string
output_string(base::StatisticsRecorder::ToJSON(std::string()));
239 base::WriteFile(output_file
, output_string
.data(),
240 static_cast<int>(output_string
.size()));
245 StartupBrowserCreator::StartupBrowserCreator()
246 : is_default_browser_dialog_suppressed_(false),
247 show_main_browser_window_(true) {
250 StartupBrowserCreator::~StartupBrowserCreator() {}
253 bool StartupBrowserCreator::was_restarted_read_
= false;
256 bool StartupBrowserCreator::in_synchronous_profile_launch_
= false;
258 void StartupBrowserCreator::AddFirstRunTab(const GURL
& url
) {
259 first_run_tabs_
.push_back(url
);
263 bool StartupBrowserCreator::InSynchronousProfileLaunch() {
264 return in_synchronous_profile_launch_
;
267 bool StartupBrowserCreator::LaunchBrowser(
268 const CommandLine
& command_line
,
270 const base::FilePath
& cur_dir
,
271 chrome::startup::IsProcessStartup process_startup
,
272 chrome::startup::IsFirstRun is_first_run
,
275 in_synchronous_profile_launch_
=
276 process_startup
== chrome::startup::IS_PROCESS_STARTUP
;
279 // Continue with the incognito profile from here on if Incognito mode
281 if (IncognitoModePrefs::ShouldLaunchIncognito(command_line
,
282 profile
->GetPrefs())) {
283 profile
= profile
->GetOffTheRecordProfile();
284 } else if (command_line
.HasSwitch(switches::kIncognito
)) {
285 LOG(WARNING
) << "Incognito mode disabled by policy, launching a normal "
286 << "browser session.";
289 // Note: This check should have been done in ProcessCmdLineImpl()
290 // before calling this function. However chromeos/login/login_utils.cc
291 // calls this function directly (see comments there) so it has to be checked
293 const bool silent_launch
= command_line
.HasSwitch(switches::kSilentLaunch
);
295 if (!silent_launch
) {
296 StartupBrowserCreatorImpl
lwp(cur_dir
, command_line
, this, is_first_run
);
297 const std::vector
<GURL
> urls_to_launch
=
298 GetURLsFromCommandLine(command_line
, cur_dir
, profile
);
299 chrome::HostDesktopType host_desktop_type
=
300 chrome::HOST_DESKTOP_TYPE_NATIVE
;
302 #if defined(OS_WIN) && defined(USE_ASH)
303 // We want to maintain only one type of instance for now, either ASH
305 // TODO(shrikant): Remove this code once we decide on running both desktop
306 // and ASH instances side by side.
307 if (ash::Shell::HasInstance())
308 host_desktop_type
= chrome::HOST_DESKTOP_TYPE_ASH
;
311 const bool launched
= lwp
.Launch(profile
, urls_to_launch
,
312 in_synchronous_profile_launch_
,
314 in_synchronous_profile_launch_
= false;
316 LOG(ERROR
) << "launch error";
318 *return_code
= chrome::RESULT_CODE_INVALID_CMDLINE_URL
;
322 in_synchronous_profile_launch_
= false;
325 profile_launch_observer
.Get().AddLaunched(profile
);
327 #if defined(OS_CHROMEOS)
328 g_browser_process
->platform_part()->profile_helper()->ProfileStartup(
336 bool StartupBrowserCreator::WasRestarted() {
337 // Stores the value of the preference kWasRestarted had when it was read.
338 static bool was_restarted
= false;
340 if (!was_restarted_read_
) {
341 PrefService
* pref_service
= g_browser_process
->local_state();
342 was_restarted
= pref_service
->GetBoolean(prefs::kWasRestarted
);
343 pref_service
->SetBoolean(prefs::kWasRestarted
, false);
344 was_restarted_read_
= true;
346 return was_restarted
;
350 SessionStartupPref
StartupBrowserCreator::GetSessionStartupPref(
351 const CommandLine
& command_line
,
354 PrefService
* prefs
= profile
->GetPrefs();
355 SessionStartupPref pref
= SessionStartupPref::GetStartupPref(prefs
);
357 // IsChromeFirstRun() looks for a sentinel file to determine whether the user
358 // is starting Chrome for the first time. On Chrome OS, the sentinel is stored
359 // in a location shared by all users and the check is meaningless. Query the
360 // UserManager instead to determine whether the user is new.
361 #if defined(OS_CHROMEOS)
362 const bool is_first_run
= chromeos::UserManager::Get()->IsCurrentUserNew();
364 const bool is_first_run
= first_run::IsChromeFirstRun();
367 // The pref has an OS-dependent default value. For the first run only, this
368 // default is overridden with SessionStartupPref::DEFAULT so that first run
369 // behavior (sync promo, welcome page) is consistently invoked.
370 // This applies only if the pref is still at its default and has not been
371 // set by the user, managed prefs or policy.
372 if (is_first_run
&& SessionStartupPref::TypeIsDefault(prefs
))
373 pref
.type
= SessionStartupPref::DEFAULT
;
375 // The switches::kRestoreLastSession command line switch is used to restore
376 // sessions after a browser self restart (e.g. after a Chrome upgrade).
377 // However, new profiles can be created from a browser process that has this
378 // switch so do not set the session pref to SessionStartupPref::LAST for
379 // those as there is nothing to restore.
380 if ((command_line
.HasSwitch(switches::kRestoreLastSession
) ||
381 StartupBrowserCreator::WasRestarted()) &&
382 !profile
->IsNewProfile()) {
383 pref
.type
= SessionStartupPref::LAST
;
385 if (pref
.type
== SessionStartupPref::LAST
&&
386 IncognitoModePrefs::ShouldLaunchIncognito(command_line
, prefs
)) {
387 // We don't store session information when incognito. If the user has
388 // chosen to restore last session and launched incognito, fallback to
389 // default launch behavior.
390 pref
.type
= SessionStartupPref::DEFAULT
;
397 void StartupBrowserCreator::ClearLaunchedProfilesForTesting() {
398 profile_launch_observer
.Get().Clear();
402 std::vector
<GURL
> StartupBrowserCreator::GetURLsFromCommandLine(
403 const CommandLine
& command_line
,
404 const base::FilePath
& cur_dir
,
406 std::vector
<GURL
> urls
;
408 const CommandLine::StringVector
& params
= command_line
.GetArgs();
409 for (size_t i
= 0; i
< params
.size(); ++i
) {
410 base::FilePath param
= base::FilePath(params
[i
]);
411 // Handle Vista way of searching - "? <search-term>"
412 if ((param
.value().size() > 2) && (param
.value()[0] == '?') &&
413 (param
.value()[1] == ' ')) {
414 GURL
url(GetDefaultSearchURLForSearchTerms(
415 profile
, param
.LossyDisplayName().substr(2)));
416 if (url
.is_valid()) {
422 // Otherwise, fall through to treating it as a URL.
424 // This will create a file URL or a regular URL.
425 // This call can (in rare circumstances) block the UI thread.
426 // Allow it until this bug is fixed.
427 // http://code.google.com/p/chromium/issues/detail?id=60641
430 base::ThreadRestrictions::ScopedAllowIO allow_io
;
431 url
= URLFixerUpper::FixupRelativeFile(cur_dir
, param
);
433 // Exclude dangerous schemes.
434 if (url
.is_valid()) {
435 ChildProcessSecurityPolicy
* policy
=
436 ChildProcessSecurityPolicy::GetInstance();
437 if (policy
->IsWebSafeScheme(url
.scheme()) ||
438 url
.SchemeIs(content::kFileScheme
) ||
439 #if defined(OS_CHROMEOS)
440 // In ChromeOS, allow a settings page to be specified on the
441 // command line. See ExistingUserController::OnLoginSuccess.
442 (url
.spec().find(chrome::kChromeUISettingsURL
) == 0) ||
444 (url
.spec().compare(content::kAboutBlankURL
) == 0)) {
453 bool StartupBrowserCreator::ProcessCmdLineImpl(
454 const CommandLine
& command_line
,
455 const base::FilePath
& cur_dir
,
456 bool process_startup
,
457 Profile
* last_used_profile
,
458 const Profiles
& last_opened_profiles
,
460 StartupBrowserCreator
* browser_creator
) {
461 DCHECK(last_used_profile
);
462 if (process_startup
) {
463 if (command_line
.HasSwitch(switches::kDisablePromptOnRepost
))
464 content::NavigationController::DisablePromptOnRepost();
467 bool silent_launch
= false;
469 #if defined(ENABLE_FULL_PRINTING)
470 // If we are just displaying a print dialog we shouldn't open browser
472 if (command_line
.HasSwitch(switches::kCloudPrintFile
) &&
473 print_dialog_cloud::CreatePrintDialogFromCommandLine(last_used_profile
,
475 silent_launch
= true;
478 // If we are checking the proxy enabled policy, don't open any windows.
479 if (command_line
.HasSwitch(switches::kCheckCloudPrintConnectorPolicy
)) {
480 silent_launch
= true;
481 if (CloudPrintProxyServiceFactory::GetForProfile(last_used_profile
)->
482 EnforceCloudPrintConnectorPolicyAndQuit())
483 // Success, nothing more needs to be done, so return false to stop
484 // launching and quit.
487 #endif // defined(ENABLE_FULL_PRINTING)
489 if (command_line
.HasSwitch(switches::kExplicitlyAllowedPorts
)) {
490 std::string allowed_ports
=
491 command_line
.GetSwitchValueASCII(switches::kExplicitlyAllowedPorts
);
492 net::SetExplicitlyAllowedPorts(allowed_ports
);
495 if (command_line
.HasSwitch(switches::kInstallFromWebstore
)) {
496 extensions::StartupHelper helper
;
497 helper
.InstallFromWebstore(command_line
, last_used_profile
);
498 // Nothing more needs to be done, so return false to stop launching and
503 if (command_line
.HasSwitch(switches::kValidateCrx
)) {
504 if (!process_startup
) {
505 LOG(ERROR
) << "chrome is already running; you must close all running "
506 << "instances before running with the --"
507 << switches::kValidateCrx
<< " flag";
510 extensions::StartupHelper helper
;
513 if (helper
.ValidateCrx(command_line
, &error
))
514 message
= std::string("ValidateCrx Success");
516 message
= std::string("ValidateCrx Failure: ") + error
;
517 printf("%s\n", message
.c_str());
521 if (command_line
.HasSwitch(switches::kLimitedInstallFromWebstore
)) {
522 extensions::StartupHelper helper
;
523 helper
.LimitedInstallFromWebstore(command_line
, last_used_profile
,
524 base::Bind(&base::DoNothing
));
527 #if defined(OS_CHROMEOS)
528 // The browser will be launched after the user logs in.
529 if (command_line
.HasSwitch(chromeos::switches::kLoginManager
) ||
530 command_line
.HasSwitch(chromeos::switches::kLoginPassword
)) {
531 silent_launch
= true;
534 if (chrome::IsRunningInAppMode() &&
535 command_line
.HasSwitch(switches::kAppId
)) {
536 chromeos::LaunchAppOrDie(
538 command_line
.GetSwitchValueASCII(switches::kAppId
));
540 // Skip browser launch since app mode launches its app window.
541 silent_launch
= true;
544 // If we are a demo app session and we crashed, there is no safe recovery
545 // possible. We should instead cleanly exit and go back to the OOBE screen,
546 // where we will launch again after the timeout has expired.
547 if (chromeos::DemoAppLauncher::IsDemoAppSession(
548 command_line
.GetSwitchValueASCII(chromeos::switches::kLoginUser
))) {
549 chrome::AttemptUserExit();
554 #if defined(TOOLKIT_VIEWS) && defined(USE_X11)
555 ui::TouchFactory::SetTouchDeviceListFromCommandLine();
558 if (!process_startup
&&
559 command_line
.HasSwitch(switches::kDumpBrowserHistograms
)) {
560 // Only handle --dump-browser-histograms from a rendezvous. In this case, do
561 // not open a new browser window even if no output file was given.
562 base::FilePath
output_file(
563 command_line
.GetSwitchValuePath(switches::kDumpBrowserHistograms
));
564 if (!output_file
.empty()) {
565 BrowserThread::PostBlockingPoolTask(
567 base::Bind(&DumpBrowserHistograms
, output_file
));
569 silent_launch
= true;
572 // If we don't want to launch a new browser window or tab we are done here.
576 // Check for --load-and-launch-app.
577 if (command_line
.HasSwitch(apps::kLoadAndLaunchApp
) &&
578 !IncognitoModePrefs::ShouldLaunchIncognito(
579 command_line
, last_used_profile
->GetPrefs())) {
580 CommandLine::StringType path
= command_line
.GetSwitchValueNative(
581 apps::kLoadAndLaunchApp
);
583 if (!apps::AppLoadService::Get(last_used_profile
)->LoadAndLaunch(
584 base::FilePath(path
), command_line
, cur_dir
)) {
588 // Return early here since we don't want to open a browser window.
589 // The exception is when there are no browser windows, since we don't want
590 // chrome to shut down.
591 // TODO(jackhou): Do this properly once keep-alive is handled by the
592 // background page of apps. Tracked at http://crbug.com/175381
593 if (chrome::GetTotalBrowserCountForProfile(last_used_profile
) != 0)
597 chrome::startup::IsProcessStartup is_process_startup
= process_startup
?
598 chrome::startup::IS_PROCESS_STARTUP
:
599 chrome::startup::IS_NOT_PROCESS_STARTUP
;
600 chrome::startup::IsFirstRun is_first_run
= first_run::IsChromeFirstRun() ?
601 chrome::startup::IS_FIRST_RUN
: chrome::startup::IS_NOT_FIRST_RUN
;
602 // |last_opened_profiles| will be empty in the following circumstances:
603 // - This is the first launch. |last_used_profile| is the initial profile.
604 // - The user exited the browser by closing all windows for all
605 // profiles. |last_used_profile| is the profile which owned the last open
607 // - Only incognito windows were open when the browser exited.
608 // |last_used_profile| is the last used incognito profile. Restoring it will
609 // create a browser window for the corresponding original profile.
610 if (last_opened_profiles
.empty()) {
611 // If the last used profile is locked or was a guest, show the user manager.
612 if (switches::IsNewProfileManagement()) {
613 ProfileInfoCache
& profile_info
=
614 g_browser_process
->profile_manager()->GetProfileInfoCache();
615 size_t profile_index
= profile_info
.GetIndexOfProfileWithPath(
616 last_used_profile
->GetPath());
617 bool signin_required
= profile_index
!= std::string::npos
&&
618 profile_info
.ProfileIsSigninRequiredAtIndex(profile_index
);
619 if (signin_required
|| last_used_profile
->IsGuestSession()) {
620 chrome::ShowUserManager(base::FilePath());
624 if (!browser_creator
->LaunchBrowser(command_line
, last_used_profile
,
625 cur_dir
, is_process_startup
,
626 is_first_run
, return_code
)) {
630 // Launch the last used profile with the full command line, and the other
631 // opened profiles without the URLs to launch.
632 CommandLine
command_line_without_urls(command_line
.GetProgram());
633 const CommandLine::SwitchMap
& switches
= command_line
.GetSwitches();
634 for (CommandLine::SwitchMap::const_iterator switch_it
= switches
.begin();
635 switch_it
!= switches
.end(); ++switch_it
) {
636 command_line_without_urls
.AppendSwitchNative(switch_it
->first
,
639 // Launch the profiles in the order they became active.
640 for (Profiles::const_iterator it
= last_opened_profiles
.begin();
641 it
!= last_opened_profiles
.end(); ++it
) {
642 // Don't launch additional profiles which would only open a new tab
643 // page. When restarting after an update, all profiles will reopen last
645 SessionStartupPref startup_pref
=
646 GetSessionStartupPref(command_line
, *it
);
647 if (*it
!= last_used_profile
&&
648 startup_pref
.type
== SessionStartupPref::DEFAULT
&&
649 !HasPendingUncleanExit(*it
))
652 // Don't re-open a browser window for the guest profile.
653 if (switches::IsNewProfileManagement() &&
654 (*it
)->IsGuestSession())
657 if (!browser_creator
->LaunchBrowser((*it
== last_used_profile
) ?
658 command_line
: command_line_without_urls
, *it
, cur_dir
,
659 is_process_startup
, is_first_run
, return_code
))
661 // We've launched at least one browser.
662 is_process_startup
= chrome::startup::IS_NOT_PROCESS_STARTUP
;
664 // This must be done after all profiles have been launched so the observer
665 // knows about all profiles to wait for before activating this one.
667 // If the last used profile was the guest one, we didn't open it so
668 // we don't need to activate it either.
669 if (!switches::IsNewProfileManagement() &&
670 !last_used_profile
->IsGuestSession())
671 profile_launch_observer
.Get().set_profile_to_activate(last_used_profile
);
677 void StartupBrowserCreator::ProcessCommandLineOnProfileCreated(
678 const CommandLine
& command_line
,
679 const base::FilePath
& cur_dir
,
681 Profile::CreateStatus status
) {
682 if (status
== Profile::CREATE_STATUS_INITIALIZED
)
683 ProcessCmdLineImpl(command_line
, cur_dir
, false, profile
, Profiles(), NULL
,
688 void StartupBrowserCreator::ProcessCommandLineAlreadyRunning(
689 const CommandLine
& command_line
,
690 const base::FilePath
& cur_dir
,
691 const base::FilePath
& profile_path
) {
692 ProfileManager
* profile_manager
= g_browser_process
->profile_manager();
693 Profile
* profile
= profile_manager
->GetProfileByPath(profile_path
);
695 // The profile isn't loaded yet and so needs to be loaded asynchronously.
697 profile_manager
->CreateProfileAsync(profile_path
,
698 base::Bind(&StartupBrowserCreator::ProcessCommandLineOnProfileCreated
,
699 command_line
, cur_dir
), base::string16(), base::string16(),
704 ProcessCmdLineImpl(command_line
, cur_dir
, false, profile
, Profiles(), NULL
,
709 bool StartupBrowserCreator::ActivatedProfile() {
710 return profile_launch_observer
.Get().activated_profile();
713 bool HasPendingUncleanExit(Profile
* profile
) {
714 return profile
->GetLastSessionExitType() == Profile::EXIT_CRASHED
&&
715 !profile_launch_observer
.Get().HasBeenLaunched(profile
);
718 base::FilePath
GetStartupProfilePath(const base::FilePath
& user_data_dir
,
719 const CommandLine
& command_line
) {
720 // If we are showing the app list then chrome isn't shown so load the app
721 // list's profile rather than chrome's.
722 if (command_line
.HasSwitch(switches::kShowAppList
)) {
723 return AppListService::Get(chrome::HOST_DESKTOP_TYPE_NATIVE
)->
724 GetProfilePath(user_data_dir
);
727 if (command_line
.HasSwitch(switches::kProfileDirectory
)) {
728 return user_data_dir
.Append(
729 command_line
.GetSwitchValuePath(switches::kProfileDirectory
));
732 return g_browser_process
->profile_manager()->GetLastUsedProfileDir(