Add a minor text member to ui::MenuModel.
[chromium-blink-merge.git] / chrome / browser / ui / startup / startup_browser_creator.cc
bloba5226e7d794ec6394796c69aa8e0d46694d14720
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/lazy_instance.h"
19 #include "base/logging.h"
20 #include "base/memory/scoped_ptr.h"
21 #include "base/metrics/histogram.h"
22 #include "base/path_service.h"
23 #include "base/prefs/pref_service.h"
24 #include "base/strings/string_number_conversions.h"
25 #include "base/strings/string_split.h"
26 #include "base/strings/utf_string_conversions.h"
27 #include "base/threading/thread_restrictions.h"
28 #include "chrome/browser/app_mode/app_mode_utils.h"
29 #include "chrome/browser/auto_launch_trial.h"
30 #include "chrome/browser/automation/automation_provider.h"
31 #include "chrome/browser/automation/automation_provider_list.h"
32 #include "chrome/browser/automation/testing_automation_provider.h"
33 #include "chrome/browser/browser_process.h"
34 #include "chrome/browser/chrome_notification_types.h"
35 #include "chrome/browser/custom_handlers/protocol_handler_registry.h"
36 #include "chrome/browser/extensions/startup_helper.h"
37 #include "chrome/browser/extensions/unpacked_installer.h"
38 #include "chrome/browser/first_run/first_run.h"
39 #include "chrome/browser/google/google_util.h"
40 #include "chrome/browser/notifications/desktop_notification_service.h"
41 #include "chrome/browser/prefs/incognito_mode_prefs.h"
42 #include "chrome/browser/prefs/session_startup_pref.h"
43 #include "chrome/browser/profiles/profile.h"
44 #include "chrome/browser/profiles/profile_manager.h"
45 #include "chrome/browser/search_engines/util.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/chrome_constants.h"
51 #include "chrome/common/chrome_paths.h"
52 #include "chrome/common/chrome_result_codes.h"
53 #include "chrome/common/chrome_switches.h"
54 #include "chrome/common/chrome_version_info.h"
55 #include "chrome/common/net/url_fixer_upper.h"
56 #include "chrome/common/pref_names.h"
57 #include "chrome/common/url_constants.h"
58 #include "chrome/installer/util/browser_distribution.h"
59 #include "content/public/browser/browser_thread.h"
60 #include "content/public/browser/child_process_security_policy.h"
61 #include "content/public/browser/navigation_controller.h"
62 #include "grit/locale_settings.h"
63 #include "net/base/net_util.h"
64 #include "ui/base/l10n/l10n_util.h"
65 #include "ui/base/resource/resource_bundle.h"
67 #if defined(OS_CHROMEOS)
68 #include "chrome/browser/chromeos/app_mode/app_launch_utils.h"
69 #include "chrome/browser/chromeos/kiosk_mode/kiosk_mode_settings.h"
70 #include "chrome/browser/chromeos/login/user_manager.h"
71 #include "chrome/browser/chromeos/profiles/profile_helper.h"
72 #include "chromeos/chromeos_switches.h"
73 #endif
75 #if defined(TOOLKIT_VIEWS) && defined(OS_LINUX)
76 #include "ui/base/touch/touch_factory_x11.h"
77 #endif
79 #if defined(OS_WIN)
80 #include "chrome/browser/automation/chrome_frame_automation_provider_win.h"
81 #include "chrome/browser/ui/startup/startup_browser_creator_win.h"
82 #endif
84 #if defined(ENABLE_FULL_PRINTING)
85 #include "chrome/browser/printing/cloud_print/cloud_print_proxy_service.h"
86 #include "chrome/browser/printing/cloud_print/cloud_print_proxy_service_factory.h"
87 #include "chrome/browser/printing/print_dialog_cloud.h"
88 #endif
90 using content::BrowserThread;
91 using content::ChildProcessSecurityPolicy;
93 namespace {
95 // Keeps track on which profiles have been launched.
96 class ProfileLaunchObserver : public content::NotificationObserver {
97 public:
98 ProfileLaunchObserver()
99 : profile_to_activate_(NULL),
100 activated_profile_(false) {
101 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
102 content::NotificationService::AllSources());
103 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_WINDOW_READY,
104 content::NotificationService::AllSources());
106 virtual ~ProfileLaunchObserver() {}
108 virtual void Observe(int type,
109 const content::NotificationSource& source,
110 const content::NotificationDetails& details) OVERRIDE {
111 switch (type) {
112 case chrome::NOTIFICATION_PROFILE_DESTROYED: {
113 Profile* profile = content::Source<Profile>(source).ptr();
114 launched_profiles_.erase(profile);
115 opened_profiles_.erase(profile);
116 if (profile == profile_to_activate_)
117 profile_to_activate_ = NULL;
118 // If this profile was the last launched one without an opened window,
119 // then we may be ready to activate |profile_to_activate_|.
120 MaybeActivateProfile();
121 break;
123 case chrome::NOTIFICATION_BROWSER_WINDOW_READY: {
124 Browser* browser = content::Source<Browser>(source).ptr();
125 DCHECK(browser);
126 opened_profiles_.insert(browser->profile());
127 MaybeActivateProfile();
128 break;
130 default:
131 NOTREACHED();
135 bool HasBeenLaunched(const Profile* profile) const {
136 return launched_profiles_.find(profile) != launched_profiles_.end();
139 void AddLaunched(Profile* profile) {
140 launched_profiles_.insert(profile);
141 // Since the startup code only executes for browsers launched in
142 // desktop mode, i.e., HOST_DESKTOP_TYPE_NATIVE. Ash should never get here.
143 if (chrome::FindBrowserWithProfile(profile,
144 chrome::HOST_DESKTOP_TYPE_NATIVE)) {
145 // A browser may get opened before we get initialized (e.g., in tests),
146 // so we never see the NOTIFICATION_BROWSER_WINDOW_READY for it.
147 opened_profiles_.insert(profile);
151 void Clear() {
152 launched_profiles_.clear();
153 opened_profiles_.clear();
156 bool activated_profile() { return activated_profile_; }
158 void set_profile_to_activate(Profile* profile) {
159 profile_to_activate_ = profile;
160 MaybeActivateProfile();
163 private:
164 void MaybeActivateProfile() {
165 if (!profile_to_activate_)
166 return;
167 // Check that browsers have been opened for all the launched profiles.
168 // Note that browsers opened for profiles that were not added as launched
169 // profiles are simply ignored.
170 std::set<const Profile*>::const_iterator i = launched_profiles_.begin();
171 for (; i != launched_profiles_.end(); ++i) {
172 if (opened_profiles_.find(*i) == opened_profiles_.end())
173 return;
175 // Asynchronous post to give a chance to the last window to completely
176 // open and activate before trying to activate |profile_to_activate_|.
177 BrowserThread::PostTask(
178 BrowserThread::UI, FROM_HERE,
179 base::Bind(&ProfileLaunchObserver::ActivateProfile,
180 base::Unretained(this)));
181 // Avoid posting more than once before ActivateProfile gets called.
182 registrar_.Remove(this, chrome::NOTIFICATION_BROWSER_WINDOW_READY,
183 content::NotificationService::AllSources());
184 registrar_.Remove(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
185 content::NotificationService::AllSources());
188 void ActivateProfile() {
189 // We need to test again, in case the profile got deleted in the mean time.
190 if (profile_to_activate_) {
191 Browser* browser = chrome::FindBrowserWithProfile(
192 profile_to_activate_, chrome::HOST_DESKTOP_TYPE_NATIVE);
193 // |profile| may never get launched, e.g., if it only had
194 // incognito Windows and one of them was used to exit Chrome.
195 // So it won't have a browser in that case.
196 if (browser)
197 browser->window()->Activate();
198 // No need try to activate this profile again.
199 profile_to_activate_ = NULL;
201 // Assign true here, even if no browser was actually activated, so that
202 // the test can stop waiting, and fail gracefully when needed.
203 activated_profile_ = true;
206 // These are the profiles that get launched by
207 // StartupBrowserCreator::LaunchBrowser.
208 std::set<const Profile*> launched_profiles_;
209 // These are the profiles for which at least one browser window has been
210 // opened. This is needed to know when it is safe to activate
211 // |profile_to_activate_|, otherwise, new browser windows being opened will
212 // be activated on top of it.
213 std::set<const Profile*> opened_profiles_;
214 content::NotificationRegistrar registrar_;
215 // This is NULL until the profile to activate has been chosen. This value,
216 // should only be set once all profiles have been launched, otherwise,
217 // activation may not happen after the launch of newer profiles.
218 Profile* profile_to_activate_;
219 // Set once we attempted to activate a profile. We only get one shot at this.
220 bool activated_profile_;
222 DISALLOW_COPY_AND_ASSIGN(ProfileLaunchObserver);
225 base::LazyInstance<ProfileLaunchObserver> profile_launch_observer =
226 LAZY_INSTANCE_INITIALIZER;
228 } // namespace
230 StartupBrowserCreator::StartupBrowserCreator()
231 : is_default_browser_dialog_suppressed_(false),
232 show_main_browser_window_(true) {
235 StartupBrowserCreator::~StartupBrowserCreator() {}
237 // static
238 bool StartupBrowserCreator::was_restarted_read_ = false;
240 // static
241 bool StartupBrowserCreator::in_synchronous_profile_launch_ = false;
243 void StartupBrowserCreator::AddFirstRunTab(const GURL& url) {
244 first_run_tabs_.push_back(url);
247 // static
248 bool StartupBrowserCreator::InSynchronousProfileLaunch() {
249 return in_synchronous_profile_launch_;
252 bool StartupBrowserCreator::LaunchBrowser(
253 const CommandLine& command_line,
254 Profile* profile,
255 const base::FilePath& cur_dir,
256 chrome::startup::IsProcessStartup process_startup,
257 chrome::startup::IsFirstRun is_first_run,
258 int* return_code) {
260 in_synchronous_profile_launch_ =
261 process_startup == chrome::startup::IS_PROCESS_STARTUP;
262 DCHECK(profile);
264 // Continue with the incognito profile from here on if Incognito mode
265 // is forced.
266 if (IncognitoModePrefs::ShouldLaunchIncognito(command_line,
267 profile->GetPrefs())) {
268 profile = profile->GetOffTheRecordProfile();
269 } else if (command_line.HasSwitch(switches::kIncognito)) {
270 LOG(WARNING) << "Incognito mode disabled by policy, launching a normal "
271 << "browser session.";
274 // Note: This check should have been done in ProcessCmdLineImpl()
275 // before calling this function. However chromeos/login/login_utils.cc
276 // calls this function directly (see comments there) so it has to be checked
277 // again.
278 const bool silent_launch = command_line.HasSwitch(switches::kSilentLaunch);
280 if (!silent_launch) {
281 StartupBrowserCreatorImpl lwp(cur_dir, command_line, this, is_first_run);
282 const std::vector<GURL> urls_to_launch =
283 GetURLsFromCommandLine(command_line, cur_dir, profile);
284 const bool launched = lwp.Launch(profile, urls_to_launch,
285 in_synchronous_profile_launch_,
286 chrome::HOST_DESKTOP_TYPE_NATIVE);
287 in_synchronous_profile_launch_ = false;
288 if (!launched) {
289 LOG(ERROR) << "launch error";
290 if (return_code)
291 *return_code = chrome::RESULT_CODE_INVALID_CMDLINE_URL;
292 return false;
294 } else {
295 in_synchronous_profile_launch_ = false;
298 profile_launch_observer.Get().AddLaunched(profile);
300 #if defined(OS_CHROMEOS)
301 chromeos::ProfileHelper::ProfileStartup(profile, process_startup);
302 #endif
303 return true;
306 // static
307 bool StartupBrowserCreator::WasRestarted() {
308 // Stores the value of the preference kWasRestarted had when it was read.
309 static bool was_restarted = false;
311 if (!was_restarted_read_) {
312 PrefService* pref_service = g_browser_process->local_state();
313 was_restarted = pref_service->GetBoolean(prefs::kWasRestarted);
314 pref_service->SetBoolean(prefs::kWasRestarted, false);
315 was_restarted_read_ = true;
317 return was_restarted;
320 // static
321 SessionStartupPref StartupBrowserCreator::GetSessionStartupPref(
322 const CommandLine& command_line,
323 Profile* profile) {
324 DCHECK(profile);
325 PrefService* prefs = profile->GetPrefs();
326 SessionStartupPref pref = SessionStartupPref::GetStartupPref(prefs);
328 // IsChromeFirstRun() looks for a sentinel file to determine whether the user
329 // is starting Chrome for the first time. On Chrome OS, the sentinel is stored
330 // in a location shared by all users and the check is meaningless. Query the
331 // UserManager instead to determine whether the user is new.
332 #if defined(OS_CHROMEOS)
333 const bool is_first_run = chromeos::UserManager::Get()->IsCurrentUserNew();
334 #else
335 const bool is_first_run = first_run::IsChromeFirstRun();
336 #endif
338 // The pref has an OS-dependent default value. For the first run only, this
339 // default is overridden with SessionStartupPref::DEFAULT so that first run
340 // behavior (sync promo, welcome page) is consistently invoked.
341 // This applies only if the pref is still at its default and has not been
342 // set by the user, managed prefs or policy.
343 if (is_first_run && SessionStartupPref::TypeIsDefault(prefs))
344 pref.type = SessionStartupPref::DEFAULT;
346 // The switches::kRestoreLastSession command line switch is used to restore
347 // sessions after a browser self restart (e.g. after a Chrome upgrade).
348 // However, new profiles can be created from a browser process that has this
349 // switch so do not set the session pref to SessionStartupPref::LAST for
350 // those as there is nothing to restore.
351 if ((command_line.HasSwitch(switches::kRestoreLastSession) ||
352 StartupBrowserCreator::WasRestarted()) &&
353 !profile->IsNewProfile()) {
354 pref.type = SessionStartupPref::LAST;
356 if (pref.type == SessionStartupPref::LAST &&
357 IncognitoModePrefs::ShouldLaunchIncognito(command_line, prefs)) {
358 // We don't store session information when incognito. If the user has
359 // chosen to restore last session and launched incognito, fallback to
360 // default launch behavior.
361 pref.type = SessionStartupPref::DEFAULT;
364 #if defined(OS_CHROMEOS)
365 // Kiosk/Retail mode has no profile to restore and fails to open the tabs
366 // specified in the startup_urls policy if we try to restore the non-existent
367 // session which is the default for ChromeOS in general.
368 if (chromeos::KioskModeSettings::Get()->IsKioskModeEnabled()) {
369 DCHECK(pref.type == SessionStartupPref::LAST);
370 pref.type = SessionStartupPref::DEFAULT;
372 #endif // OS_CHROMEOS
374 return pref;
377 // static
378 void StartupBrowserCreator::ClearLaunchedProfilesForTesting() {
379 profile_launch_observer.Get().Clear();
382 // static
383 std::vector<GURL> StartupBrowserCreator::GetURLsFromCommandLine(
384 const CommandLine& command_line,
385 const base::FilePath& cur_dir,
386 Profile* profile) {
387 std::vector<GURL> urls;
389 const CommandLine::StringVector& params = command_line.GetArgs();
390 for (size_t i = 0; i < params.size(); ++i) {
391 base::FilePath param = base::FilePath(params[i]);
392 // Handle Vista way of searching - "? <search-term>"
393 if ((param.value().size() > 2) && (param.value()[0] == '?') &&
394 (param.value()[1] == ' ')) {
395 GURL url(GetDefaultSearchURLForSearchTerms(
396 profile, param.LossyDisplayName().substr(2)));
397 if (url.is_valid()) {
398 urls.push_back(url);
399 continue;
403 // Otherwise, fall through to treating it as a URL.
405 // This will create a file URL or a regular URL.
406 // This call can (in rare circumstances) block the UI thread.
407 // Allow it until this bug is fixed.
408 // http://code.google.com/p/chromium/issues/detail?id=60641
409 GURL url;
411 base::ThreadRestrictions::ScopedAllowIO allow_io;
412 url = URLFixerUpper::FixupRelativeFile(cur_dir, param);
414 // Exclude dangerous schemes.
415 if (url.is_valid()) {
416 ChildProcessSecurityPolicy* policy =
417 ChildProcessSecurityPolicy::GetInstance();
418 if (policy->IsWebSafeScheme(url.scheme()) ||
419 url.SchemeIs(chrome::kFileScheme) ||
420 #if defined(OS_CHROMEOS)
421 // In ChromeOS, allow a settings page to be specified on the
422 // command line. See ExistingUserController::OnLoginSuccess.
423 (url.spec().find(chrome::kChromeUISettingsURL) == 0) ||
424 #endif
425 (url.spec().compare(content::kAboutBlankURL) == 0)) {
426 urls.push_back(url);
430 #if defined(OS_WIN)
431 if (urls.empty()) {
432 // If we are in Windows 8 metro mode and were launched as a result of the
433 // search charm or via a url navigation in metro, then fetch the
434 // corresponding url.
435 GURL url(chrome::GetURLToOpen(profile));
436 if (url.is_valid())
437 urls.push_back(url);
439 #endif // OS_WIN
440 return urls;
443 // static
444 bool StartupBrowserCreator::ProcessCmdLineImpl(
445 const CommandLine& command_line,
446 const base::FilePath& cur_dir,
447 bool process_startup,
448 Profile* last_used_profile,
449 const Profiles& last_opened_profiles,
450 int* return_code,
451 StartupBrowserCreator* browser_creator) {
452 DCHECK(last_used_profile);
453 if (process_startup) {
454 if (command_line.HasSwitch(switches::kDisablePromptOnRepost))
455 content::NavigationController::DisablePromptOnRepost();
458 bool silent_launch = false;
460 #if defined(ENABLE_AUTOMATION)
461 // Look for the testing channel ID ONLY during process startup
462 if (process_startup &&
463 command_line.HasSwitch(switches::kTestingChannelID)) {
464 std::string testing_channel_id = command_line.GetSwitchValueASCII(
465 switches::kTestingChannelID);
466 // TODO(sanjeevr) Check if we need to make this a singleton for
467 // compatibility with the old testing code
468 // If there are any extra parameters, we expect each one to generate a
469 // new tab; if there are none then we get one homepage tab.
470 int expected_tab_count = 1;
471 if (command_line.HasSwitch(switches::kNoStartupWindow) &&
472 !command_line.HasSwitch(switches::kAutoLaunchAtStartup)) {
473 expected_tab_count = 0;
474 #if defined(OS_CHROMEOS)
475 // kLoginManager will cause Chrome to start up with the ChromeOS login
476 // screen instead of a browser window, so it won't load any tabs.
477 } else if (command_line.HasSwitch(chromeos::switches::kLoginManager)) {
478 expected_tab_count = 0;
479 #endif
480 } else if (command_line.HasSwitch(switches::kRestoreLastSession)) {
481 std::string restore_session_value(
482 command_line.GetSwitchValueASCII(switches::kRestoreLastSession));
483 base::StringToInt(restore_session_value, &expected_tab_count);
484 } else {
485 std::vector<GURL> urls_to_open = GetURLsFromCommandLine(
486 command_line, cur_dir, last_used_profile);
487 expected_tab_count =
488 std::max(1, static_cast<int>(urls_to_open.size()));
490 if (!CreateAutomationProvider<TestingAutomationProvider>(
491 testing_channel_id,
492 last_used_profile,
493 static_cast<size_t>(expected_tab_count)))
494 return false;
497 if (command_line.HasSwitch(switches::kSilentLaunch)) {
498 std::vector<GURL> urls_to_open = GetURLsFromCommandLine(
499 command_line, cur_dir, last_used_profile);
500 size_t expected_tabs =
501 std::max(static_cast<int>(urls_to_open.size()), 0);
502 if (expected_tabs == 0)
503 silent_launch = true;
506 if (command_line.HasSwitch(switches::kAutomationClientChannelID)) {
507 std::string automation_channel_id = command_line.GetSwitchValueASCII(
508 switches::kAutomationClientChannelID);
509 // If there are any extra parameters, we expect each one to generate a
510 // new tab; if there are none then we have no tabs
511 std::vector<GURL> urls_to_open = GetURLsFromCommandLine(
512 command_line, cur_dir, last_used_profile);
513 size_t expected_tabs =
514 std::max(static_cast<int>(urls_to_open.size()), 0);
515 if (expected_tabs == 0)
516 silent_launch = true;
518 if (command_line.HasSwitch(switches::kChromeFrame)) {
519 #if defined(OS_WIN)
520 if (!CreateAutomationProvider<ChromeFrameAutomationProvider>(
521 automation_channel_id, last_used_profile, expected_tabs))
522 return false;
523 #endif
524 } else {
525 if (!CreateAutomationProvider<AutomationProvider>(
526 automation_channel_id, last_used_profile, expected_tabs))
527 return false;
530 #endif // defined(ENABLE_AUTOMATION)
532 #if defined(ENABLE_FULL_PRINTING)
533 // If we are just displaying a print dialog we shouldn't open browser
534 // windows.
535 if (command_line.HasSwitch(switches::kCloudPrintFile) &&
536 print_dialog_cloud::CreatePrintDialogFromCommandLine(command_line)) {
537 silent_launch = true;
540 // If we are checking the proxy enabled policy, don't open any windows.
541 if (command_line.HasSwitch(switches::kCheckCloudPrintConnectorPolicy)) {
542 silent_launch = true;
543 if (CloudPrintProxyServiceFactory::GetForProfile(last_used_profile)->
544 EnforceCloudPrintConnectorPolicyAndQuit())
545 // Success, nothing more needs to be done, so return false to stop
546 // launching and quit.
547 return false;
549 #endif // defined(ENABLE_FULL_PRINTING)
551 if (command_line.HasSwitch(switches::kExplicitlyAllowedPorts)) {
552 std::string allowed_ports =
553 command_line.GetSwitchValueASCII(switches::kExplicitlyAllowedPorts);
554 net::SetExplicitlyAllowedPorts(allowed_ports);
557 if (command_line.HasSwitch(switches::kInstallFromWebstore)) {
558 extensions::StartupHelper helper;
559 helper.InstallFromWebstore(command_line, last_used_profile);
560 // Nothing more needs to be done, so return false to stop launching and
561 // quit.
562 return false;
565 if (command_line.HasSwitch(switches::kValidateCrx)) {
566 if (!process_startup) {
567 LOG(ERROR) << "chrome is already running; you must close all running "
568 << "instances before running with the --"
569 << switches::kValidateCrx << " flag";
570 return false;
572 extensions::StartupHelper helper;
573 std::string message;
574 std::string error;
575 if (helper.ValidateCrx(command_line, &error))
576 message = std::string("ValidateCrx Success");
577 else
578 message = std::string("ValidateCrx Failure: ") + error;
579 printf("%s\n", message.c_str());
580 return false;
583 if (command_line.HasSwitch(switches::kLimitedInstallFromWebstore)) {
584 extensions::StartupHelper helper;
585 helper.LimitedInstallFromWebstore(command_line, last_used_profile,
586 base::Bind(&base::DoNothing));
589 #if defined(OS_CHROMEOS)
590 // The browser will be launched after the user logs in.
591 if (command_line.HasSwitch(chromeos::switches::kLoginManager) ||
592 command_line.HasSwitch(chromeos::switches::kLoginPassword)) {
593 silent_launch = true;
596 if (chrome::IsRunningInAppMode() &&
597 command_line.HasSwitch(switches::kAppId)) {
598 chromeos::LaunchAppOrDie(
599 last_used_profile,
600 command_line.GetSwitchValueASCII(switches::kAppId));
602 // Skip browser launch since app mode launches its app window.
603 silent_launch = true;
605 #endif
607 #if defined(TOOLKIT_VIEWS) && defined(USE_X11)
608 ui::TouchFactory::SetTouchDeviceListFromCommandLine();
609 #endif
611 // If we don't want to launch a new browser window or tab (in the case
612 // of an automation request), we are done here.
613 if (silent_launch)
614 return true;
616 // Check for --load-and-launch-app.
617 if (command_line.HasSwitch(apps::kLoadAndLaunchApp) &&
618 !IncognitoModePrefs::ShouldLaunchIncognito(
619 command_line, last_used_profile->GetPrefs())) {
620 CommandLine::StringType path = command_line.GetSwitchValueNative(
621 apps::kLoadAndLaunchApp);
623 if (!apps::AppLoadService::Get(last_used_profile)->LoadAndLaunch(
624 base::FilePath(path), command_line, cur_dir)) {
625 return false;
628 // Return early here since we don't want to open a browser window.
629 // The exception is when there are no browser windows, since we don't want
630 // chrome to shut down.
631 // TODO(jackhou): Do this properly once keep-alive is handled by the
632 // background page of apps. Tracked at http://crbug.com/175381
633 if (chrome::GetTotalBrowserCountForProfile(last_used_profile) != 0)
634 return true;
637 chrome::startup::IsProcessStartup is_process_startup = process_startup ?
638 chrome::startup::IS_PROCESS_STARTUP :
639 chrome::startup::IS_NOT_PROCESS_STARTUP;
640 chrome::startup::IsFirstRun is_first_run = first_run::IsChromeFirstRun() ?
641 chrome::startup::IS_FIRST_RUN : chrome::startup::IS_NOT_FIRST_RUN;
642 // |last_opened_profiles| will be empty in the following circumstances:
643 // - This is the first launch. |last_used_profile| is the initial profile.
644 // - The user exited the browser by closing all windows for all
645 // profiles. |last_used_profile| is the profile which owned the last open
646 // window.
647 // - Only incognito windows were open when the browser exited.
648 // |last_used_profile| is the last used incognito profile. Restoring it will
649 // create a browser window for the corresponding original profile.
650 if (last_opened_profiles.empty()) {
651 if (!browser_creator->LaunchBrowser(command_line, last_used_profile,
652 cur_dir, is_process_startup,
653 is_first_run, return_code)) {
654 return false;
656 } else {
657 // Launch the last used profile with the full command line, and the other
658 // opened profiles without the URLs to launch.
659 CommandLine command_line_without_urls(command_line.GetProgram());
660 const CommandLine::SwitchMap& switches = command_line.GetSwitches();
661 for (CommandLine::SwitchMap::const_iterator switch_it = switches.begin();
662 switch_it != switches.end(); ++switch_it) {
663 command_line_without_urls.AppendSwitchNative(switch_it->first,
664 switch_it->second);
666 // Launch the profiles in the order they became active.
667 for (Profiles::const_iterator it = last_opened_profiles.begin();
668 it != last_opened_profiles.end(); ++it) {
669 // Don't launch additional profiles which would only open a new tab
670 // page. When restarting after an update, all profiles will reopen last
671 // open pages.
672 SessionStartupPref startup_pref =
673 GetSessionStartupPref(command_line, *it);
674 if (*it != last_used_profile &&
675 startup_pref.type == SessionStartupPref::DEFAULT &&
676 !HasPendingUncleanExit(*it))
677 continue;
678 if (!browser_creator->LaunchBrowser((*it == last_used_profile) ?
679 command_line : command_line_without_urls, *it, cur_dir,
680 is_process_startup, is_first_run, return_code))
681 return false;
682 // We've launched at least one browser.
683 is_process_startup = chrome::startup::IS_NOT_PROCESS_STARTUP;
685 // This must be done after all profiles have been launched so the observer
686 // knows about all profiles to wait for before activating this one.
687 profile_launch_observer.Get().set_profile_to_activate(last_used_profile);
689 return true;
692 template <class AutomationProviderClass>
693 bool StartupBrowserCreator::CreateAutomationProvider(
694 const std::string& channel_id,
695 Profile* profile,
696 size_t expected_tabs) {
697 #if defined(ENABLE_AUTOMATION)
698 scoped_refptr<AutomationProviderClass> automation =
699 new AutomationProviderClass(profile);
700 if (!automation->InitializeChannel(channel_id))
701 return false;
702 automation->SetExpectedTabCount(expected_tabs);
704 AutomationProviderList* list = g_browser_process->GetAutomationProviderList();
705 DCHECK(list);
706 list->AddProvider(automation.get());
707 #endif // defined(ENABLE_AUTOMATION)
709 return true;
712 // static
713 void StartupBrowserCreator::ProcessCommandLineOnProfileCreated(
714 const CommandLine& command_line,
715 const base::FilePath& cur_dir,
716 Profile* profile,
717 Profile::CreateStatus status) {
718 if (status == Profile::CREATE_STATUS_INITIALIZED)
719 ProcessCmdLineImpl(command_line, cur_dir, false, profile, Profiles(), NULL,
720 NULL);
723 // static
724 void StartupBrowserCreator::ProcessCommandLineAlreadyRunning(
725 const CommandLine& command_line,
726 const base::FilePath& cur_dir,
727 const base::FilePath& profile_path) {
728 ProfileManager* profile_manager = g_browser_process->profile_manager();
729 Profile* profile = profile_manager->GetProfileByPath(profile_path);
731 // The profile isn't loaded yet and so needs to be loaded asynchronously.
732 if (!profile) {
733 profile_manager->CreateProfileAsync(profile_path,
734 base::Bind(&StartupBrowserCreator::ProcessCommandLineOnProfileCreated,
735 command_line, cur_dir), string16(), string16(),
736 std::string());
737 return;
740 ProcessCmdLineImpl(command_line, cur_dir, false, profile, Profiles(), NULL,
741 NULL);
744 // static
745 bool StartupBrowserCreator::ActivatedProfile() {
746 return profile_launch_observer.Get().activated_profile();
749 bool HasPendingUncleanExit(Profile* profile) {
750 return profile->GetLastSessionExitType() == Profile::EXIT_CRASHED &&
751 !profile_launch_observer.Get().HasBeenLaunched(profile);