Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / ui / startup / startup_browser_creator.cc
blobc5663e12484a50bbfeea08960ef0e2ddd6d953d1
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 "ash/shell.h"
13 #include "base/bind.h"
14 #include "base/bind_helpers.h"
15 #include "base/command_line.h"
16 #include "base/compiler_specific.h"
17 #include "base/environment.h"
18 #include "base/file_util.h"
19 #include "base/files/file_path.h"
20 #include "base/lazy_instance.h"
21 #include "base/logging.h"
22 #include "base/memory/scoped_ptr.h"
23 #include "base/metrics/histogram.h"
24 #include "base/metrics/statistics_recorder.h"
25 #include "base/path_service.h"
26 #include "base/prefs/pref_service.h"
27 #include "base/strings/string_number_conversions.h"
28 #include "base/strings/string_split.h"
29 #include "base/strings/utf_string_conversions.h"
30 #include "base/threading/thread_restrictions.h"
31 #include "chrome/browser/app_mode/app_mode_utils.h"
32 #include "chrome/browser/auto_launch_trial.h"
33 #include "chrome/browser/automation/automation_provider.h"
34 #include "chrome/browser/automation/automation_provider_list.h"
35 #include "chrome/browser/automation/testing_automation_provider.h"
36 #include "chrome/browser/browser_process.h"
37 #include "chrome/browser/chrome_notification_types.h"
38 #include "chrome/browser/custom_handlers/protocol_handler_registry.h"
39 #include "chrome/browser/extensions/startup_helper.h"
40 #include "chrome/browser/extensions/unpacked_installer.h"
41 #include "chrome/browser/first_run/first_run.h"
42 #include "chrome/browser/google/google_util.h"
43 #include "chrome/browser/notifications/desktop_notification_service.h"
44 #include "chrome/browser/prefs/incognito_mode_prefs.h"
45 #include "chrome/browser/prefs/session_startup_pref.h"
46 #include "chrome/browser/profiles/profile.h"
47 #include "chrome/browser/profiles/profile_manager.h"
48 #include "chrome/browser/profiles/profiles_state.h"
49 #include "chrome/browser/search_engines/util.h"
50 #include "chrome/browser/ui/app_list/app_list_service.h"
51 #include "chrome/browser/ui/browser.h"
52 #include "chrome/browser/ui/browser_dialogs.h"
53 #include "chrome/browser/ui/browser_finder.h"
54 #include "chrome/browser/ui/browser_window.h"
55 #include "chrome/browser/ui/startup/startup_browser_creator_impl.h"
56 #include "chrome/common/chrome_constants.h"
57 #include "chrome/common/chrome_paths.h"
58 #include "chrome/common/chrome_result_codes.h"
59 #include "chrome/common/chrome_switches.h"
60 #include "chrome/common/chrome_version_info.h"
61 #include "chrome/common/net/url_fixer_upper.h"
62 #include "chrome/common/pref_names.h"
63 #include "chrome/common/profile_management_switches.h"
64 #include "chrome/common/url_constants.h"
65 #include "chrome/installer/util/browser_distribution.h"
66 #include "content/public/browser/browser_thread.h"
67 #include "content/public/browser/child_process_security_policy.h"
68 #include "content/public/browser/navigation_controller.h"
69 #include "grit/locale_settings.h"
70 #include "net/base/net_util.h"
71 #include "ui/base/l10n/l10n_util.h"
72 #include "ui/base/resource/resource_bundle.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/user_manager.h"
78 #include "chrome/browser/chromeos/profiles/profile_helper.h"
79 #include "chromeos/chromeos_switches.h"
80 #endif
82 #if defined(TOOLKIT_VIEWS) && defined(OS_LINUX)
83 #include "ui/events/x/touch_factory_x11.h"
84 #endif
86 #if defined(OS_WIN)
87 #include "chrome/browser/ui/startup/startup_browser_creator_win.h"
88 #endif
90 #if defined(ENABLE_FULL_PRINTING)
91 #include "chrome/browser/printing/cloud_print/cloud_print_proxy_service.h"
92 #include "chrome/browser/printing/cloud_print/cloud_print_proxy_service_factory.h"
93 #include "chrome/browser/printing/print_dialog_cloud.h"
94 #endif
96 using content::BrowserThread;
97 using content::ChildProcessSecurityPolicy;
99 namespace {
101 // Keeps track on which profiles have been launched.
102 class ProfileLaunchObserver : public content::NotificationObserver {
103 public:
104 ProfileLaunchObserver()
105 : profile_to_activate_(NULL),
106 activated_profile_(false) {
107 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
108 content::NotificationService::AllSources());
109 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_WINDOW_READY,
110 content::NotificationService::AllSources());
112 virtual ~ProfileLaunchObserver() {}
114 virtual void Observe(int type,
115 const content::NotificationSource& source,
116 const content::NotificationDetails& details) OVERRIDE {
117 switch (type) {
118 case chrome::NOTIFICATION_PROFILE_DESTROYED: {
119 Profile* profile = content::Source<Profile>(source).ptr();
120 launched_profiles_.erase(profile);
121 opened_profiles_.erase(profile);
122 if (profile == profile_to_activate_)
123 profile_to_activate_ = NULL;
124 // If this profile was the last launched one without an opened window,
125 // then we may be ready to activate |profile_to_activate_|.
126 MaybeActivateProfile();
127 break;
129 case chrome::NOTIFICATION_BROWSER_WINDOW_READY: {
130 Browser* browser = content::Source<Browser>(source).ptr();
131 DCHECK(browser);
132 opened_profiles_.insert(browser->profile());
133 MaybeActivateProfile();
134 break;
136 default:
137 NOTREACHED();
141 bool HasBeenLaunched(const Profile* profile) const {
142 return launched_profiles_.find(profile) != launched_profiles_.end();
145 void AddLaunched(Profile* profile) {
146 launched_profiles_.insert(profile);
147 // Since the startup code only executes for browsers launched in
148 // desktop mode, i.e., HOST_DESKTOP_TYPE_NATIVE. Ash should never get here.
149 if (chrome::FindBrowserWithProfile(profile,
150 chrome::HOST_DESKTOP_TYPE_NATIVE)) {
151 // A browser may get opened before we get initialized (e.g., in tests),
152 // so we never see the NOTIFICATION_BROWSER_WINDOW_READY for it.
153 opened_profiles_.insert(profile);
157 void Clear() {
158 launched_profiles_.clear();
159 opened_profiles_.clear();
162 bool activated_profile() { return activated_profile_; }
164 void set_profile_to_activate(Profile* profile) {
165 profile_to_activate_ = profile;
166 MaybeActivateProfile();
169 private:
170 void MaybeActivateProfile() {
171 if (!profile_to_activate_)
172 return;
173 // Check that browsers have been opened for all the launched profiles.
174 // Note that browsers opened for profiles that were not added as launched
175 // profiles are simply ignored.
176 std::set<const Profile*>::const_iterator i = launched_profiles_.begin();
177 for (; i != launched_profiles_.end(); ++i) {
178 if (opened_profiles_.find(*i) == opened_profiles_.end())
179 return;
181 // Asynchronous post to give a chance to the last window to completely
182 // open and activate before trying to activate |profile_to_activate_|.
183 BrowserThread::PostTask(
184 BrowserThread::UI, FROM_HERE,
185 base::Bind(&ProfileLaunchObserver::ActivateProfile,
186 base::Unretained(this)));
187 // Avoid posting more than once before ActivateProfile gets called.
188 registrar_.Remove(this, chrome::NOTIFICATION_BROWSER_WINDOW_READY,
189 content::NotificationService::AllSources());
190 registrar_.Remove(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
191 content::NotificationService::AllSources());
194 void ActivateProfile() {
195 // We need to test again, in case the profile got deleted in the mean time.
196 if (profile_to_activate_) {
197 Browser* browser = chrome::FindBrowserWithProfile(
198 profile_to_activate_, chrome::HOST_DESKTOP_TYPE_NATIVE);
199 // |profile| may never get launched, e.g., if it only had
200 // incognito Windows and one of them was used to exit Chrome.
201 // So it won't have a browser in that case.
202 if (browser)
203 browser->window()->Activate();
204 // No need try to activate this profile again.
205 profile_to_activate_ = NULL;
207 // Assign true here, even if no browser was actually activated, so that
208 // the test can stop waiting, and fail gracefully when needed.
209 activated_profile_ = true;
212 // These are the profiles that get launched by
213 // StartupBrowserCreator::LaunchBrowser.
214 std::set<const Profile*> launched_profiles_;
215 // These are the profiles for which at least one browser window has been
216 // opened. This is needed to know when it is safe to activate
217 // |profile_to_activate_|, otherwise, new browser windows being opened will
218 // be activated on top of it.
219 std::set<const Profile*> opened_profiles_;
220 content::NotificationRegistrar registrar_;
221 // This is NULL until the profile to activate has been chosen. This value,
222 // should only be set once all profiles have been launched, otherwise,
223 // activation may not happen after the launch of newer profiles.
224 Profile* profile_to_activate_;
225 // Set once we attempted to activate a profile. We only get one shot at this.
226 bool activated_profile_;
228 DISALLOW_COPY_AND_ASSIGN(ProfileLaunchObserver);
231 base::LazyInstance<ProfileLaunchObserver> profile_launch_observer =
232 LAZY_INSTANCE_INITIALIZER;
234 // Dumps the current set of the browser process's histograms to |output_file|.
235 // The file is overwritten if it exists. This function should only be called in
236 // the blocking pool.
237 void DumpBrowserHistograms(const base::FilePath& output_file) {
238 base::ThreadRestrictions::AssertIOAllowed();
240 std::string output_string(base::StatisticsRecorder::ToJSON(std::string()));
241 file_util::WriteFile(output_file, output_string.data(),
242 static_cast<int>(output_string.size()));
245 } // namespace
247 StartupBrowserCreator::StartupBrowserCreator()
248 : is_default_browser_dialog_suppressed_(false),
249 show_main_browser_window_(true) {
252 StartupBrowserCreator::~StartupBrowserCreator() {}
254 // static
255 bool StartupBrowserCreator::was_restarted_read_ = false;
257 // static
258 bool StartupBrowserCreator::in_synchronous_profile_launch_ = false;
260 void StartupBrowserCreator::AddFirstRunTab(const GURL& url) {
261 first_run_tabs_.push_back(url);
264 // static
265 bool StartupBrowserCreator::InSynchronousProfileLaunch() {
266 return in_synchronous_profile_launch_;
269 bool StartupBrowserCreator::LaunchBrowser(
270 const CommandLine& command_line,
271 Profile* profile,
272 const base::FilePath& cur_dir,
273 chrome::startup::IsProcessStartup process_startup,
274 chrome::startup::IsFirstRun is_first_run,
275 int* return_code) {
277 in_synchronous_profile_launch_ =
278 process_startup == chrome::startup::IS_PROCESS_STARTUP;
279 DCHECK(profile);
281 // Continue with the incognito profile from here on if Incognito mode
282 // is forced.
283 if (IncognitoModePrefs::ShouldLaunchIncognito(command_line,
284 profile->GetPrefs())) {
285 profile = profile->GetOffTheRecordProfile();
286 } else if (command_line.HasSwitch(switches::kIncognito)) {
287 LOG(WARNING) << "Incognito mode disabled by policy, launching a normal "
288 << "browser session.";
291 // Note: This check should have been done in ProcessCmdLineImpl()
292 // before calling this function. However chromeos/login/login_utils.cc
293 // calls this function directly (see comments there) so it has to be checked
294 // again.
295 const bool silent_launch = command_line.HasSwitch(switches::kSilentLaunch);
297 if (!silent_launch) {
298 StartupBrowserCreatorImpl lwp(cur_dir, command_line, this, is_first_run);
299 const std::vector<GURL> urls_to_launch =
300 GetURLsFromCommandLine(command_line, cur_dir, profile);
301 chrome::HostDesktopType host_desktop_type =
302 chrome::HOST_DESKTOP_TYPE_NATIVE;
304 #if defined(OS_WIN) && defined(USE_ASH)
305 // We want to maintain only one type of instance for now, either ASH
306 // or desktop.
307 // TODO(shrikant): Remove this code once we decide on running both desktop
308 // and ASH instances side by side.
309 if (ash::Shell::HasInstance())
310 host_desktop_type = chrome::HOST_DESKTOP_TYPE_ASH;
311 #endif
313 const bool launched = lwp.Launch(profile, urls_to_launch,
314 in_synchronous_profile_launch_,
315 host_desktop_type);
316 in_synchronous_profile_launch_ = false;
317 if (!launched) {
318 LOG(ERROR) << "launch error";
319 if (return_code)
320 *return_code = chrome::RESULT_CODE_INVALID_CMDLINE_URL;
321 return false;
323 } else {
324 in_synchronous_profile_launch_ = false;
327 profile_launch_observer.Get().AddLaunched(profile);
329 #if defined(OS_CHROMEOS)
330 g_browser_process->platform_part()->profile_helper()->ProfileStartup(
331 profile,
332 process_startup);
333 #endif
334 return true;
337 // static
338 bool StartupBrowserCreator::WasRestarted() {
339 // Stores the value of the preference kWasRestarted had when it was read.
340 static bool was_restarted = false;
342 if (!was_restarted_read_) {
343 PrefService* pref_service = g_browser_process->local_state();
344 was_restarted = pref_service->GetBoolean(prefs::kWasRestarted);
345 pref_service->SetBoolean(prefs::kWasRestarted, false);
346 was_restarted_read_ = true;
348 return was_restarted;
351 // static
352 SessionStartupPref StartupBrowserCreator::GetSessionStartupPref(
353 const CommandLine& command_line,
354 Profile* profile) {
355 DCHECK(profile);
356 PrefService* prefs = profile->GetPrefs();
357 SessionStartupPref pref = SessionStartupPref::GetStartupPref(prefs);
359 // IsChromeFirstRun() looks for a sentinel file to determine whether the user
360 // is starting Chrome for the first time. On Chrome OS, the sentinel is stored
361 // in a location shared by all users and the check is meaningless. Query the
362 // UserManager instead to determine whether the user is new.
363 #if defined(OS_CHROMEOS)
364 const bool is_first_run = chromeos::UserManager::Get()->IsCurrentUserNew();
365 #else
366 const bool is_first_run = first_run::IsChromeFirstRun();
367 #endif
369 // The pref has an OS-dependent default value. For the first run only, this
370 // default is overridden with SessionStartupPref::DEFAULT so that first run
371 // behavior (sync promo, welcome page) is consistently invoked.
372 // This applies only if the pref is still at its default and has not been
373 // set by the user, managed prefs or policy.
374 if (is_first_run && SessionStartupPref::TypeIsDefault(prefs))
375 pref.type = SessionStartupPref::DEFAULT;
377 // The switches::kRestoreLastSession command line switch is used to restore
378 // sessions after a browser self restart (e.g. after a Chrome upgrade).
379 // However, new profiles can be created from a browser process that has this
380 // switch so do not set the session pref to SessionStartupPref::LAST for
381 // those as there is nothing to restore.
382 if ((command_line.HasSwitch(switches::kRestoreLastSession) ||
383 StartupBrowserCreator::WasRestarted()) &&
384 !profile->IsNewProfile()) {
385 pref.type = SessionStartupPref::LAST;
387 if (pref.type == SessionStartupPref::LAST &&
388 IncognitoModePrefs::ShouldLaunchIncognito(command_line, prefs)) {
389 // We don't store session information when incognito. If the user has
390 // chosen to restore last session and launched incognito, fallback to
391 // default launch behavior.
392 pref.type = SessionStartupPref::DEFAULT;
395 return pref;
398 // static
399 void StartupBrowserCreator::ClearLaunchedProfilesForTesting() {
400 profile_launch_observer.Get().Clear();
403 // static
404 std::vector<GURL> StartupBrowserCreator::GetURLsFromCommandLine(
405 const CommandLine& command_line,
406 const base::FilePath& cur_dir,
407 Profile* profile) {
408 std::vector<GURL> urls;
410 const CommandLine::StringVector& params = command_line.GetArgs();
411 for (size_t i = 0; i < params.size(); ++i) {
412 base::FilePath param = base::FilePath(params[i]);
413 // Handle Vista way of searching - "? <search-term>"
414 if ((param.value().size() > 2) && (param.value()[0] == '?') &&
415 (param.value()[1] == ' ')) {
416 GURL url(GetDefaultSearchURLForSearchTerms(
417 profile, param.LossyDisplayName().substr(2)));
418 if (url.is_valid()) {
419 urls.push_back(url);
420 continue;
424 // Otherwise, fall through to treating it as a URL.
426 // This will create a file URL or a regular URL.
427 // This call can (in rare circumstances) block the UI thread.
428 // Allow it until this bug is fixed.
429 // http://code.google.com/p/chromium/issues/detail?id=60641
430 GURL url;
432 base::ThreadRestrictions::ScopedAllowIO allow_io;
433 url = URLFixerUpper::FixupRelativeFile(cur_dir, param);
435 // Exclude dangerous schemes.
436 if (url.is_valid()) {
437 ChildProcessSecurityPolicy* policy =
438 ChildProcessSecurityPolicy::GetInstance();
439 if (policy->IsWebSafeScheme(url.scheme()) ||
440 url.SchemeIs(content::kFileScheme) ||
441 #if defined(OS_CHROMEOS)
442 // In ChromeOS, allow a settings page to be specified on the
443 // command line. See ExistingUserController::OnLoginSuccess.
444 (url.spec().find(chrome::kChromeUISettingsURL) == 0) ||
445 #endif
446 (url.spec().compare(content::kAboutBlankURL) == 0)) {
447 urls.push_back(url);
451 #if defined(OS_WIN)
452 if (urls.empty()) {
453 // If we are in Windows 8 metro mode and were launched as a result of the
454 // search charm or via a url navigation in metro, then fetch the
455 // corresponding url.
456 GURL url(chrome::GetURLToOpen(profile));
457 if (url.is_valid())
458 urls.push_back(url);
460 #endif // OS_WIN
461 return urls;
464 // static
465 bool StartupBrowserCreator::ProcessCmdLineImpl(
466 const CommandLine& command_line,
467 const base::FilePath& cur_dir,
468 bool process_startup,
469 Profile* last_used_profile,
470 const Profiles& last_opened_profiles,
471 int* return_code,
472 StartupBrowserCreator* browser_creator) {
473 DCHECK(last_used_profile);
474 if (process_startup) {
475 if (command_line.HasSwitch(switches::kDisablePromptOnRepost))
476 content::NavigationController::DisablePromptOnRepost();
479 bool silent_launch = false;
481 #if defined(ENABLE_AUTOMATION)
482 // Look for the testing channel ID ONLY during process startup
483 if (process_startup &&
484 command_line.HasSwitch(switches::kTestingChannelID)) {
485 std::string testing_channel_id = command_line.GetSwitchValueASCII(
486 switches::kTestingChannelID);
487 // TODO(sanjeevr) Check if we need to make this a singleton for
488 // compatibility with the old testing code
489 // If there are any extra parameters, we expect each one to generate a
490 // new tab; if there are none then we get one homepage tab.
491 int expected_tab_count = 1;
492 if (command_line.HasSwitch(switches::kNoStartupWindow) &&
493 !command_line.HasSwitch(switches::kAutoLaunchAtStartup)) {
494 expected_tab_count = 0;
495 #if defined(OS_CHROMEOS)
496 // kLoginManager will cause Chrome to start up with the ChromeOS login
497 // screen instead of a browser window, so it won't load any tabs.
498 } else if (command_line.HasSwitch(chromeos::switches::kLoginManager)) {
499 expected_tab_count = 0;
500 #endif
501 } else if (command_line.HasSwitch(switches::kRestoreLastSession)) {
502 std::string restore_session_value(
503 command_line.GetSwitchValueASCII(switches::kRestoreLastSession));
504 base::StringToInt(restore_session_value, &expected_tab_count);
505 } else {
506 std::vector<GURL> urls_to_open = GetURLsFromCommandLine(
507 command_line, cur_dir, last_used_profile);
508 expected_tab_count =
509 std::max(1, static_cast<int>(urls_to_open.size()));
511 if (!CreateAutomationProvider<TestingAutomationProvider>(
512 testing_channel_id,
513 last_used_profile,
514 static_cast<size_t>(expected_tab_count)))
515 return false;
518 if (command_line.HasSwitch(switches::kSilentLaunch)) {
519 std::vector<GURL> urls_to_open = GetURLsFromCommandLine(
520 command_line, cur_dir, last_used_profile);
521 size_t expected_tabs =
522 std::max(static_cast<int>(urls_to_open.size()), 0);
523 if (expected_tabs == 0)
524 silent_launch = true;
527 if (command_line.HasSwitch(switches::kAutomationClientChannelID)) {
528 std::string automation_channel_id = command_line.GetSwitchValueASCII(
529 switches::kAutomationClientChannelID);
530 // If there are any extra parameters, we expect each one to generate a
531 // new tab; if there are none then we have no tabs
532 std::vector<GURL> urls_to_open = GetURLsFromCommandLine(
533 command_line, cur_dir, last_used_profile);
534 size_t expected_tabs =
535 std::max(static_cast<int>(urls_to_open.size()), 0);
536 if (expected_tabs == 0)
537 silent_launch = true;
539 if (!CreateAutomationProvider<AutomationProvider>(
540 automation_channel_id, last_used_profile, expected_tabs))
541 return false;
543 #endif // defined(ENABLE_AUTOMATION)
545 #if defined(ENABLE_FULL_PRINTING)
546 // If we are just displaying a print dialog we shouldn't open browser
547 // windows.
548 if (command_line.HasSwitch(switches::kCloudPrintFile) &&
549 print_dialog_cloud::CreatePrintDialogFromCommandLine(last_used_profile,
550 command_line)) {
551 silent_launch = true;
554 // If we are checking the proxy enabled policy, don't open any windows.
555 if (command_line.HasSwitch(switches::kCheckCloudPrintConnectorPolicy)) {
556 silent_launch = true;
557 if (CloudPrintProxyServiceFactory::GetForProfile(last_used_profile)->
558 EnforceCloudPrintConnectorPolicyAndQuit())
559 // Success, nothing more needs to be done, so return false to stop
560 // launching and quit.
561 return false;
563 #endif // defined(ENABLE_FULL_PRINTING)
565 if (command_line.HasSwitch(switches::kExplicitlyAllowedPorts)) {
566 std::string allowed_ports =
567 command_line.GetSwitchValueASCII(switches::kExplicitlyAllowedPorts);
568 net::SetExplicitlyAllowedPorts(allowed_ports);
571 if (command_line.HasSwitch(switches::kInstallFromWebstore)) {
572 extensions::StartupHelper helper;
573 helper.InstallFromWebstore(command_line, last_used_profile);
574 // Nothing more needs to be done, so return false to stop launching and
575 // quit.
576 return false;
579 if (command_line.HasSwitch(switches::kValidateCrx)) {
580 if (!process_startup) {
581 LOG(ERROR) << "chrome is already running; you must close all running "
582 << "instances before running with the --"
583 << switches::kValidateCrx << " flag";
584 return false;
586 extensions::StartupHelper helper;
587 std::string message;
588 std::string error;
589 if (helper.ValidateCrx(command_line, &error))
590 message = std::string("ValidateCrx Success");
591 else
592 message = std::string("ValidateCrx Failure: ") + error;
593 printf("%s\n", message.c_str());
594 return false;
597 if (command_line.HasSwitch(switches::kLimitedInstallFromWebstore)) {
598 extensions::StartupHelper helper;
599 helper.LimitedInstallFromWebstore(command_line, last_used_profile,
600 base::Bind(&base::DoNothing));
603 #if defined(OS_CHROMEOS)
604 // The browser will be launched after the user logs in.
605 if (command_line.HasSwitch(chromeos::switches::kLoginManager) ||
606 command_line.HasSwitch(chromeos::switches::kLoginPassword)) {
607 silent_launch = true;
610 if (chrome::IsRunningInAppMode() &&
611 command_line.HasSwitch(switches::kAppId)) {
612 chromeos::LaunchAppOrDie(
613 last_used_profile,
614 command_line.GetSwitchValueASCII(switches::kAppId));
616 // Skip browser launch since app mode launches its app window.
617 silent_launch = true;
619 #endif
621 #if defined(TOOLKIT_VIEWS) && defined(USE_X11)
622 ui::TouchFactory::SetTouchDeviceListFromCommandLine();
623 #endif
625 if (!process_startup &&
626 command_line.HasSwitch(switches::kDumpBrowserHistograms)) {
627 // Only handle --dump-browser-histograms from a rendezvous. In this case, do
628 // not open a new browser window even if no output file was given.
629 base::FilePath output_file(
630 command_line.GetSwitchValuePath(switches::kDumpBrowserHistograms));
631 if (!output_file.empty()) {
632 BrowserThread::PostBlockingPoolTask(
633 FROM_HERE,
634 base::Bind(&DumpBrowserHistograms, output_file));
636 silent_launch = true;
639 // If we don't want to launch a new browser window or tab (in the case
640 // of an automation request), we are done here.
641 if (silent_launch)
642 return true;
644 // Check for --load-and-launch-app.
645 if (command_line.HasSwitch(apps::kLoadAndLaunchApp) &&
646 !IncognitoModePrefs::ShouldLaunchIncognito(
647 command_line, last_used_profile->GetPrefs())) {
648 CommandLine::StringType path = command_line.GetSwitchValueNative(
649 apps::kLoadAndLaunchApp);
651 if (!apps::AppLoadService::Get(last_used_profile)->LoadAndLaunch(
652 base::FilePath(path), command_line, cur_dir)) {
653 return false;
656 // Return early here since we don't want to open a browser window.
657 // The exception is when there are no browser windows, since we don't want
658 // chrome to shut down.
659 // TODO(jackhou): Do this properly once keep-alive is handled by the
660 // background page of apps. Tracked at http://crbug.com/175381
661 if (chrome::GetTotalBrowserCountForProfile(last_used_profile) != 0)
662 return true;
665 chrome::startup::IsProcessStartup is_process_startup = process_startup ?
666 chrome::startup::IS_PROCESS_STARTUP :
667 chrome::startup::IS_NOT_PROCESS_STARTUP;
668 chrome::startup::IsFirstRun is_first_run = first_run::IsChromeFirstRun() ?
669 chrome::startup::IS_FIRST_RUN : chrome::startup::IS_NOT_FIRST_RUN;
670 // |last_opened_profiles| will be empty in the following circumstances:
671 // - This is the first launch. |last_used_profile| is the initial profile.
672 // - The user exited the browser by closing all windows for all
673 // profiles. |last_used_profile| is the profile which owned the last open
674 // window.
675 // - Only incognito windows were open when the browser exited.
676 // |last_used_profile| is the last used incognito profile. Restoring it will
677 // create a browser window for the corresponding original profile.
678 if (last_opened_profiles.empty()) {
679 // If the last used profile was a guest, show the user manager instead.
680 if (switches::IsNewProfileManagement() &&
681 last_used_profile->IsGuestSession()) {
682 chrome::ShowUserManager(base::FilePath());
683 return true;
685 if (!browser_creator->LaunchBrowser(command_line, last_used_profile,
686 cur_dir, is_process_startup,
687 is_first_run, return_code)) {
688 return false;
690 } else {
691 // Launch the last used profile with the full command line, and the other
692 // opened profiles without the URLs to launch.
693 CommandLine command_line_without_urls(command_line.GetProgram());
694 const CommandLine::SwitchMap& switches = command_line.GetSwitches();
695 for (CommandLine::SwitchMap::const_iterator switch_it = switches.begin();
696 switch_it != switches.end(); ++switch_it) {
697 command_line_without_urls.AppendSwitchNative(switch_it->first,
698 switch_it->second);
700 // Launch the profiles in the order they became active.
701 for (Profiles::const_iterator it = last_opened_profiles.begin();
702 it != last_opened_profiles.end(); ++it) {
703 // Don't launch additional profiles which would only open a new tab
704 // page. When restarting after an update, all profiles will reopen last
705 // open pages.
706 SessionStartupPref startup_pref =
707 GetSessionStartupPref(command_line, *it);
708 if (*it != last_used_profile &&
709 startup_pref.type == SessionStartupPref::DEFAULT &&
710 !HasPendingUncleanExit(*it))
711 continue;
713 // Don't re-open a browser window for the guest profile.
714 if (switches::IsNewProfileManagement() &&
715 (*it)->IsGuestSession())
716 continue;
718 if (!browser_creator->LaunchBrowser((*it == last_used_profile) ?
719 command_line : command_line_without_urls, *it, cur_dir,
720 is_process_startup, is_first_run, return_code))
721 return false;
722 // We've launched at least one browser.
723 is_process_startup = chrome::startup::IS_NOT_PROCESS_STARTUP;
725 // This must be done after all profiles have been launched so the observer
726 // knows about all profiles to wait for before activating this one.
728 // If the last used profile was the guest one, we didn't open it so
729 // we don't need to activate it either.
730 if (!switches::IsNewProfileManagement() &&
731 !last_used_profile->IsGuestSession())
732 profile_launch_observer.Get().set_profile_to_activate(last_used_profile);
734 return true;
737 template <class AutomationProviderClass>
738 bool StartupBrowserCreator::CreateAutomationProvider(
739 const std::string& channel_id,
740 Profile* profile,
741 size_t expected_tabs) {
742 #if defined(ENABLE_AUTOMATION)
743 scoped_refptr<AutomationProviderClass> automation =
744 new AutomationProviderClass(profile);
745 if (!automation->InitializeChannel(channel_id))
746 return false;
747 automation->SetExpectedTabCount(expected_tabs);
749 AutomationProviderList* list = g_browser_process->GetAutomationProviderList();
750 DCHECK(list);
751 list->AddProvider(automation.get());
752 #endif // defined(ENABLE_AUTOMATION)
754 return true;
757 // static
758 void StartupBrowserCreator::ProcessCommandLineOnProfileCreated(
759 const CommandLine& command_line,
760 const base::FilePath& cur_dir,
761 Profile* profile,
762 Profile::CreateStatus status) {
763 if (status == Profile::CREATE_STATUS_INITIALIZED)
764 ProcessCmdLineImpl(command_line, cur_dir, false, profile, Profiles(), NULL,
765 NULL);
768 // static
769 void StartupBrowserCreator::ProcessCommandLineAlreadyRunning(
770 const CommandLine& command_line,
771 const base::FilePath& cur_dir,
772 const base::FilePath& profile_path) {
773 ProfileManager* profile_manager = g_browser_process->profile_manager();
774 Profile* profile = profile_manager->GetProfileByPath(profile_path);
776 // The profile isn't loaded yet and so needs to be loaded asynchronously.
777 if (!profile) {
778 profile_manager->CreateProfileAsync(profile_path,
779 base::Bind(&StartupBrowserCreator::ProcessCommandLineOnProfileCreated,
780 command_line, cur_dir), base::string16(), base::string16(),
781 std::string());
782 return;
785 ProcessCmdLineImpl(command_line, cur_dir, false, profile, Profiles(), NULL,
786 NULL);
789 // static
790 bool StartupBrowserCreator::ActivatedProfile() {
791 return profile_launch_observer.Get().activated_profile();
794 bool HasPendingUncleanExit(Profile* profile) {
795 return profile->GetLastSessionExitType() == Profile::EXIT_CRASHED &&
796 !profile_launch_observer.Get().HasBeenLaunched(profile);
799 base::FilePath GetStartupProfilePath(const base::FilePath& user_data_dir,
800 const CommandLine& command_line) {
801 // If we are showing the app list then chrome isn't shown so load the app
802 // list's profile rather than chrome's.
803 if (command_line.HasSwitch(switches::kShowAppList)) {
804 return AppListService::Get(chrome::HOST_DESKTOP_TYPE_NATIVE)->
805 GetProfilePath(user_data_dir);
808 if (command_line.HasSwitch(switches::kProfileDirectory)) {
809 return user_data_dir.Append(
810 command_line.GetSwitchValuePath(switches::kProfileDirectory));
813 return g_browser_process->profile_manager()->GetLastUsedProfileDir(
814 user_data_dir);