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