Update V8 to version 4.6.22.
[chromium-blink-merge.git] / chrome / browser / ui / startup / startup_browser_creator.cc
blobd654cc874e6a1a61ec78aa8d7ef7cc2154623540
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/ui/startup/startup_browser_creator.h"
7 #include <algorithm> // For max().
8 #include <set>
10 #include "apps/app_load_service.h"
11 #include "apps/switches.h"
12 #include "base/bind.h"
13 #include "base/bind_helpers.h"
14 #include "base/command_line.h"
15 #include "base/compiler_specific.h"
16 #include "base/environment.h"
17 #include "base/files/file_path.h"
18 #include "base/files/file_util.h"
19 #include "base/lazy_instance.h"
20 #include "base/logging.h"
21 #include "base/memory/scoped_ptr.h"
22 #include "base/metrics/histogram_macros.h"
23 #include "base/metrics/statistics_recorder.h"
24 #include "base/prefs/pref_registry_simple.h"
25 #include "base/prefs/pref_service.h"
26 #include "base/profiler/scoped_profile.h"
27 #include "base/strings/string_number_conversions.h"
28 #include "base/strings/string_split.h"
29 #include "base/strings/string_tokenizer.h"
30 #include "base/strings/utf_string_conversions.h"
31 #include "base/threading/thread_restrictions.h"
32 #include "base/trace_event/trace_event.h"
33 #include "chrome/browser/app_mode/app_mode_utils.h"
34 #include "chrome/browser/auto_launch_trial.h"
35 #include "chrome/browser/browser_process.h"
36 #include "chrome/browser/chrome_notification_types.h"
37 #include "chrome/browser/custom_handlers/protocol_handler_registry.h"
38 #include "chrome/browser/extensions/startup_helper.h"
39 #include "chrome/browser/extensions/unpacked_installer.h"
40 #include "chrome/browser/first_run/first_run.h"
41 #include "chrome/browser/notifications/desktop_notification_service.h"
42 #include "chrome/browser/prefs/incognito_mode_prefs.h"
43 #include "chrome/browser/prefs/session_startup_pref.h"
44 #include "chrome/browser/profiles/profile.h"
45 #include "chrome/browser/profiles/profile_manager.h"
46 #include "chrome/browser/profiles/profiles_state.h"
47 #include "chrome/browser/search_engines/template_url_service_factory.h"
48 #include "chrome/browser/ui/app_list/app_list_service.h"
49 #include "chrome/browser/ui/browser.h"
50 #include "chrome/browser/ui/browser_dialogs.h"
51 #include "chrome/browser/ui/browser_finder.h"
52 #include "chrome/browser/ui/browser_window.h"
53 #include "chrome/browser/ui/startup/startup_browser_creator_impl.h"
54 #include "chrome/browser/ui/user_manager.h"
55 #include "chrome/common/chrome_constants.h"
56 #include "chrome/common/chrome_paths.h"
57 #include "chrome/common/chrome_result_codes.h"
58 #include "chrome/common/chrome_switches.h"
59 #include "chrome/common/chrome_version_info.h"
60 #include "chrome/common/pref_names.h"
61 #include "chrome/common/url_constants.h"
62 #include "chrome/installer/util/browser_distribution.h"
63 #include "components/google/core/browser/google_util.h"
64 #include "components/search_engines/util.h"
65 #include "components/signin/core/common/profile_management_switches.h"
66 #include "components/url_fixer/url_fixer.h"
67 #include "content/public/browser/browser_thread.h"
68 #include "content/public/browser/child_process_security_policy.h"
69 #include "content/public/browser/navigation_controller.h"
70 #include "content/public/common/content_switches.h"
71 #include "extensions/common/switches.h"
72 #include "net/base/port_util.h"
74 #if defined(USE_ASH)
75 #include "ash/shell.h"
76 #endif
78 #if defined(OS_CHROMEOS)
79 #include "chrome/browser/chromeos/app_mode/app_launch_utils.h"
80 #include "chrome/browser/chromeos/login/demo_mode/demo_app_launcher.h"
81 #include "chrome/browser/chromeos/profiles/profile_helper.h"
82 #include "chrome/browser/lifetime/application_lifetime.h"
83 #include "chromeos/chromeos_switches.h"
84 #include "components/user_manager/user_manager.h"
85 #endif
87 #if defined(TOOLKIT_VIEWS) && defined(OS_LINUX)
88 #include "ui/events/devices/x11/touch_factory_x11.h"
89 #endif
91 #if defined(OS_MACOSX)
92 #include "chrome/browser/web_applications/web_app_mac.h"
93 #endif
95 #if defined(OS_WIN)
96 #include "chrome/browser/metrics/jumplist_metrics_win.h"
97 #endif
99 #if defined(ENABLE_PRINT_PREVIEW)
100 #include "chrome/browser/printing/cloud_print/cloud_print_proxy_service.h"
101 #include "chrome/browser/printing/cloud_print/cloud_print_proxy_service_factory.h"
102 #include "chrome/browser/printing/print_dialog_cloud.h"
103 #endif
105 using content::BrowserThread;
106 using content::ChildProcessSecurityPolicy;
108 namespace {
110 // Keeps track on which profiles have been launched.
111 class ProfileLaunchObserver : public content::NotificationObserver {
112 public:
113 ProfileLaunchObserver()
114 : profile_to_activate_(NULL),
115 activated_profile_(false) {
116 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
117 content::NotificationService::AllSources());
118 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_WINDOW_READY,
119 content::NotificationService::AllSources());
121 ~ProfileLaunchObserver() override {}
123 void Observe(int type,
124 const content::NotificationSource& source,
125 const content::NotificationDetails& details) override {
126 switch (type) {
127 case chrome::NOTIFICATION_PROFILE_DESTROYED: {
128 Profile* profile = content::Source<Profile>(source).ptr();
129 launched_profiles_.erase(profile);
130 opened_profiles_.erase(profile);
131 if (profile == profile_to_activate_)
132 profile_to_activate_ = NULL;
133 // If this profile was the last launched one without an opened window,
134 // then we may be ready to activate |profile_to_activate_|.
135 MaybeActivateProfile();
136 break;
138 case chrome::NOTIFICATION_BROWSER_WINDOW_READY: {
139 Browser* browser = content::Source<Browser>(source).ptr();
140 DCHECK(browser);
141 opened_profiles_.insert(browser->profile());
142 MaybeActivateProfile();
143 break;
145 default:
146 NOTREACHED();
150 bool HasBeenLaunched(const Profile* profile) const {
151 return launched_profiles_.find(profile) != launched_profiles_.end();
154 void AddLaunched(Profile* profile) {
155 launched_profiles_.insert(profile);
156 // Since the startup code only executes for browsers launched in
157 // desktop mode, i.e., HOST_DESKTOP_TYPE_NATIVE. Ash should never get here.
158 if (chrome::FindBrowserWithProfile(profile,
159 chrome::HOST_DESKTOP_TYPE_NATIVE)) {
160 // A browser may get opened before we get initialized (e.g., in tests),
161 // so we never see the NOTIFICATION_BROWSER_WINDOW_READY for it.
162 opened_profiles_.insert(profile);
166 void Clear() {
167 launched_profiles_.clear();
168 opened_profiles_.clear();
171 bool activated_profile() { return activated_profile_; }
173 void set_profile_to_activate(Profile* profile) {
174 profile_to_activate_ = profile;
175 MaybeActivateProfile();
178 private:
179 void MaybeActivateProfile() {
180 if (!profile_to_activate_)
181 return;
182 // Check that browsers have been opened for all the launched profiles.
183 // Note that browsers opened for profiles that were not added as launched
184 // profiles are simply ignored.
185 std::set<const Profile*>::const_iterator i = launched_profiles_.begin();
186 for (; i != launched_profiles_.end(); ++i) {
187 if (opened_profiles_.find(*i) == opened_profiles_.end())
188 return;
190 // Asynchronous post to give a chance to the last window to completely
191 // open and activate before trying to activate |profile_to_activate_|.
192 BrowserThread::PostTask(
193 BrowserThread::UI, FROM_HERE,
194 base::Bind(&ProfileLaunchObserver::ActivateProfile,
195 base::Unretained(this)));
196 // Avoid posting more than once before ActivateProfile gets called.
197 registrar_.Remove(this, chrome::NOTIFICATION_BROWSER_WINDOW_READY,
198 content::NotificationService::AllSources());
199 registrar_.Remove(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
200 content::NotificationService::AllSources());
203 void ActivateProfile() {
204 // We need to test again, in case the profile got deleted in the mean time.
205 if (profile_to_activate_) {
206 Browser* browser = chrome::FindBrowserWithProfile(
207 profile_to_activate_, chrome::HOST_DESKTOP_TYPE_NATIVE);
208 // |profile| may never get launched, e.g., if it only had
209 // incognito Windows and one of them was used to exit Chrome.
210 // So it won't have a browser in that case.
211 if (browser)
212 browser->window()->Activate();
213 // No need try to activate this profile again.
214 profile_to_activate_ = NULL;
216 // Assign true here, even if no browser was actually activated, so that
217 // the test can stop waiting, and fail gracefully when needed.
218 activated_profile_ = true;
221 // These are the profiles that get launched by
222 // StartupBrowserCreator::LaunchBrowser.
223 std::set<const Profile*> launched_profiles_;
224 // These are the profiles for which at least one browser window has been
225 // opened. This is needed to know when it is safe to activate
226 // |profile_to_activate_|, otherwise, new browser windows being opened will
227 // be activated on top of it.
228 std::set<const Profile*> opened_profiles_;
229 content::NotificationRegistrar registrar_;
230 // This is NULL until the profile to activate has been chosen. This value,
231 // should only be set once all profiles have been launched, otherwise,
232 // activation may not happen after the launch of newer profiles.
233 Profile* profile_to_activate_;
234 // Set once we attempted to activate a profile. We only get one shot at this.
235 bool activated_profile_;
237 DISALLOW_COPY_AND_ASSIGN(ProfileLaunchObserver);
240 base::LazyInstance<ProfileLaunchObserver> profile_launch_observer =
241 LAZY_INSTANCE_INITIALIZER;
243 // Dumps the current set of the browser process's histograms to |output_file|.
244 // The file is overwritten if it exists. This function should only be called in
245 // the blocking pool.
246 void DumpBrowserHistograms(const base::FilePath& output_file) {
247 base::ThreadRestrictions::AssertIOAllowed();
249 std::string output_string(base::StatisticsRecorder::ToJSON(std::string()));
250 base::WriteFile(output_file, output_string.data(),
251 static_cast<int>(output_string.size()));
254 } // namespace
256 StartupBrowserCreator::StartupBrowserCreator()
257 : is_default_browser_dialog_suppressed_(false),
258 show_main_browser_window_(true) {
261 StartupBrowserCreator::~StartupBrowserCreator() {}
263 // static
264 bool StartupBrowserCreator::was_restarted_read_ = false;
266 // static
267 bool StartupBrowserCreator::in_synchronous_profile_launch_ = false;
269 void StartupBrowserCreator::AddFirstRunTab(const GURL& url) {
270 first_run_tabs_.push_back(url);
273 bool StartupBrowserCreator::Start(const base::CommandLine& cmd_line,
274 const base::FilePath& cur_dir,
275 Profile* last_used_profile,
276 const Profiles& last_opened_profiles) {
277 TRACE_EVENT0("startup", "StartupBrowserCreator::Start");
278 TRACK_SCOPED_REGION("Startup", "StartupBrowserCreator::Start");
279 SCOPED_UMA_HISTOGRAM_TIMER("Startup.StartupBrowserCreator_Start");
280 return ProcessCmdLineImpl(cmd_line, cur_dir, true, last_used_profile,
281 last_opened_profiles, this);
284 // static
285 bool StartupBrowserCreator::InSynchronousProfileLaunch() {
286 return in_synchronous_profile_launch_;
289 bool StartupBrowserCreator::LaunchBrowser(
290 const base::CommandLine& command_line,
291 Profile* profile,
292 const base::FilePath& cur_dir,
293 chrome::startup::IsProcessStartup process_startup,
294 chrome::startup::IsFirstRun is_first_run) {
295 in_synchronous_profile_launch_ =
296 process_startup == chrome::startup::IS_PROCESS_STARTUP;
297 DCHECK(profile);
299 // Continue with the incognito profile from here on if Incognito mode
300 // is forced.
301 if (IncognitoModePrefs::ShouldLaunchIncognito(command_line,
302 profile->GetPrefs())) {
303 profile = profile->GetOffTheRecordProfile();
304 } else if (command_line.HasSwitch(switches::kIncognito)) {
305 LOG(WARNING) << "Incognito mode disabled by policy, launching a normal "
306 << "browser session.";
309 // Note: This check should have been done in ProcessCmdLineImpl()
310 // before calling this function. However chromeos/login/login_utils.cc
311 // calls this function directly (see comments there) so it has to be checked
312 // again.
313 const bool silent_launch = command_line.HasSwitch(switches::kSilentLaunch);
315 if (!silent_launch) {
316 StartupBrowserCreatorImpl lwp(cur_dir, command_line, this, is_first_run);
317 const std::vector<GURL> urls_to_launch =
318 GetURLsFromCommandLine(command_line, cur_dir, profile);
319 chrome::HostDesktopType host_desktop_type =
320 chrome::HOST_DESKTOP_TYPE_NATIVE;
322 #if defined(USE_ASH) && !defined(OS_CHROMEOS)
323 // We want to maintain only one type of instance for now, either ASH
324 // or desktop.
325 // TODO(shrikant): Remove this code once we decide on running both desktop
326 // and ASH instances side by side.
327 if (ash::Shell::HasInstance())
328 host_desktop_type = chrome::HOST_DESKTOP_TYPE_ASH;
329 #endif
331 const bool launched = lwp.Launch(profile, urls_to_launch,
332 in_synchronous_profile_launch_,
333 host_desktop_type);
334 in_synchronous_profile_launch_ = false;
335 if (!launched) {
336 LOG(ERROR) << "launch error";
337 return false;
339 } else {
340 in_synchronous_profile_launch_ = false;
343 profile_launch_observer.Get().AddLaunched(profile);
345 #if defined(OS_CHROMEOS)
346 chromeos::ProfileHelper::Get()->ProfileStartup(profile, process_startup);
347 #endif
348 return true;
351 // static
352 bool StartupBrowserCreator::WasRestarted() {
353 // Stores the value of the preference kWasRestarted had when it was read.
354 static bool was_restarted = false;
356 if (!was_restarted_read_) {
357 PrefService* pref_service = g_browser_process->local_state();
358 was_restarted = pref_service->GetBoolean(prefs::kWasRestarted);
359 pref_service->SetBoolean(prefs::kWasRestarted, false);
360 was_restarted_read_ = true;
362 return was_restarted;
365 // static
366 SessionStartupPref StartupBrowserCreator::GetSessionStartupPref(
367 const base::CommandLine& command_line,
368 Profile* profile) {
369 DCHECK(profile);
370 PrefService* prefs = profile->GetPrefs();
371 SessionStartupPref pref = SessionStartupPref::GetStartupPref(prefs);
373 // IsChromeFirstRun() looks for a sentinel file to determine whether the user
374 // is starting Chrome for the first time. On Chrome OS, the sentinel is stored
375 // in a location shared by all users and the check is meaningless. Query the
376 // UserManager instead to determine whether the user is new.
377 #if defined(OS_CHROMEOS)
378 const bool is_first_run =
379 user_manager::UserManager::Get()->IsCurrentUserNew();
380 // On ChromeOS restarts force the user to login again. The expectation is that
381 // after a login the user gets clean state. For this reason we ignore
382 // StartupBrowserCreator::WasRestarted().
383 const bool did_restart = false;
384 #else
385 const bool is_first_run = first_run::IsChromeFirstRun();
386 const bool did_restart = StartupBrowserCreator::WasRestarted();
387 #endif
389 // The pref has an OS-dependent default value. For the first run only, this
390 // default is overridden with SessionStartupPref::DEFAULT so that first run
391 // behavior (sync promo, welcome page) is consistently invoked.
392 // This applies only if the pref is still at its default and has not been
393 // set by the user, managed prefs or policy.
394 if (is_first_run && SessionStartupPref::TypeIsDefault(prefs))
395 pref.type = SessionStartupPref::DEFAULT;
397 // The switches::kRestoreLastSession command line switch is used to restore
398 // sessions after a browser self restart (e.g. after a Chrome upgrade).
399 // However, new profiles can be created from a browser process that has this
400 // switch so do not set the session pref to SessionStartupPref::LAST for
401 // those as there is nothing to restore.
402 if ((command_line.HasSwitch(switches::kRestoreLastSession) || did_restart) &&
403 !profile->IsNewProfile()) {
404 pref.type = SessionStartupPref::LAST;
407 // A browser starting for a profile being unlocked should always restore.
408 if (!profile->IsGuestSession()) {
409 ProfileInfoCache& info_cache =
410 g_browser_process->profile_manager()->GetProfileInfoCache();
411 size_t index = info_cache.GetIndexOfProfileWithPath(profile->GetPath());
413 if (index != std::string::npos &&
414 info_cache.ProfileIsSigninRequiredAtIndex(index)) {
415 pref.type = SessionStartupPref::LAST;
419 if (pref.type == SessionStartupPref::LAST &&
420 IncognitoModePrefs::ShouldLaunchIncognito(command_line, prefs)) {
421 // We don't store session information when incognito. If the user has
422 // chosen to restore last session and launched incognito, fallback to
423 // default launch behavior.
424 pref.type = SessionStartupPref::DEFAULT;
427 return pref;
430 // static
431 void StartupBrowserCreator::ClearLaunchedProfilesForTesting() {
432 profile_launch_observer.Get().Clear();
435 // static
436 void StartupBrowserCreator::RegisterLocalStatePrefs(
437 PrefRegistrySimple* registry) {
438 #if defined(OS_WIN)
439 registry->RegisterStringPref(prefs::kLastWelcomedOSVersion, std::string());
440 registry->RegisterBooleanPref(prefs::kWelcomePageOnOSUpgradeEnabled, true);
441 #endif
444 // static
445 std::vector<GURL> StartupBrowserCreator::GetURLsFromCommandLine(
446 const base::CommandLine& command_line,
447 const base::FilePath& cur_dir,
448 Profile* profile) {
449 std::vector<GURL> urls;
451 const base::CommandLine::StringVector& params = command_line.GetArgs();
452 for (size_t i = 0; i < params.size(); ++i) {
453 base::FilePath param = base::FilePath(params[i]);
454 // Handle Vista way of searching - "? <search-term>"
455 if ((param.value().size() > 2) && (param.value()[0] == '?') &&
456 (param.value()[1] == ' ')) {
457 GURL url(GetDefaultSearchURLForSearchTerms(
458 TemplateURLServiceFactory::GetForProfile(profile),
459 param.LossyDisplayName().substr(2)));
460 if (url.is_valid()) {
461 urls.push_back(url);
462 continue;
466 // Otherwise, fall through to treating it as a URL.
468 // This will create a file URL or a regular URL.
469 // This call can (in rare circumstances) block the UI thread.
470 // Allow it until this bug is fixed.
471 // http://code.google.com/p/chromium/issues/detail?id=60641
472 GURL url = GURL(param.MaybeAsASCII());
473 // http://crbug.com/371030: Only use URLFixerUpper if we don't have a valid
474 // URL, otherwise we will look in the current directory for a file named
475 // 'about' if the browser was started with a about:foo argument.
476 if (!url.is_valid()) {
477 base::ThreadRestrictions::ScopedAllowIO allow_io;
478 url = url_fixer::FixupRelativeFile(cur_dir, param);
480 // Exclude dangerous schemes.
481 if (url.is_valid()) {
482 ChildProcessSecurityPolicy* policy =
483 ChildProcessSecurityPolicy::GetInstance();
484 if (policy->IsWebSafeScheme(url.scheme()) ||
485 url.SchemeIs(url::kFileScheme) ||
486 #if defined(OS_CHROMEOS)
487 // In ChromeOS, allow any settings page to be specified on the command
488 // line. See ExistingUserController::OnLoginSuccess.
489 (url.spec().find(chrome::kChromeUISettingsURL) == 0) ||
490 #else
491 ((url.spec().find(std::string(chrome::kChromeUISettingsURL) +
492 chrome::kResetProfileSettingsSubPage) == 0)) ||
493 #endif
494 (url.spec().compare(url::kAboutBlankURL) == 0)) {
495 urls.push_back(url);
499 return urls;
502 // static
503 bool StartupBrowserCreator::ProcessCmdLineImpl(
504 const base::CommandLine& command_line,
505 const base::FilePath& cur_dir,
506 bool process_startup,
507 Profile* last_used_profile,
508 const Profiles& last_opened_profiles,
509 StartupBrowserCreator* browser_creator) {
510 TRACE_EVENT0("startup", "StartupBrowserCreator::ProcessCmdLineImpl");
512 VLOG(2) << "ProcessCmdLineImpl : BEGIN";
513 DCHECK(last_used_profile);
514 if (process_startup) {
515 if (command_line.HasSwitch(switches::kDisablePromptOnRepost))
516 content::NavigationController::DisablePromptOnRepost();
519 bool silent_launch = false;
521 #if defined(ENABLE_PRINT_PREVIEW)
522 // If we are just displaying a print dialog we shouldn't open browser
523 // windows.
524 if (command_line.HasSwitch(switches::kCloudPrintFile) &&
525 print_dialog_cloud::CreatePrintDialogFromCommandLine(last_used_profile,
526 command_line)) {
527 silent_launch = true;
529 #endif // defined(ENABLE_PRINT_PREVIEW)
531 VLOG(2) << "ProcessCmdLineImpl: PLACE 1";
532 if (command_line.HasSwitch(switches::kExplicitlyAllowedPorts)) {
533 std::string allowed_ports =
534 command_line.GetSwitchValueASCII(switches::kExplicitlyAllowedPorts);
535 net::SetExplicitlyAllowedPorts(allowed_ports);
538 if (command_line.HasSwitch(switches::kInstallEphemeralAppFromWebstore)) {
539 extensions::StartupHelper helper;
540 helper.InstallEphemeralApp(command_line, last_used_profile);
541 // Nothing more needs to be done, so return false to stop launching and
542 // quit.
543 return false;
546 VLOG(2) << "ProcessCmdLineImpl: PLACE 2";
547 if (command_line.HasSwitch(switches::kValidateCrx)) {
548 if (!process_startup) {
549 LOG(ERROR) << "chrome is already running; you must close all running "
550 << "instances before running with the --"
551 << switches::kValidateCrx << " flag";
552 return false;
554 extensions::StartupHelper helper;
555 std::string message;
556 std::string error;
557 if (helper.ValidateCrx(command_line, &error))
558 message = std::string("ValidateCrx Success");
559 else
560 message = std::string("ValidateCrx Failure: ") + error;
561 printf("%s\n", message.c_str());
562 return false;
565 #if defined(OS_CHROMEOS)
567 // The browser will be launched after the user logs in.
568 if (command_line.HasSwitch(chromeos::switches::kLoginManager))
569 silent_launch = true;
571 if (chrome::IsRunningInAppMode() &&
572 command_line.HasSwitch(switches::kAppId)) {
573 chromeos::LaunchAppOrDie(
574 last_used_profile,
575 command_line.GetSwitchValueASCII(switches::kAppId));
577 // Skip browser launch since app mode launches its app window.
578 silent_launch = true;
581 // If we are a demo app session and we crashed, there is no safe recovery
582 // possible. We should instead cleanly exit and go back to the OOBE screen,
583 // where we will launch again after the timeout has expired.
584 if (chromeos::DemoAppLauncher::IsDemoAppSession(
585 command_line.GetSwitchValueASCII(chromeos::switches::kLoginUser))) {
586 chrome::AttemptUserExit();
587 return false;
589 #endif // OS_CHROMEOS
591 #if defined(TOOLKIT_VIEWS) && defined(USE_X11)
592 ui::TouchFactory::SetTouchDeviceListFromCommandLine();
593 #endif
595 VLOG(2) << "ProcessCmdLineImpl: PLACE 3";
596 #if defined(OS_MACOSX)
597 if (web_app::MaybeRebuildShortcut(command_line))
598 return true;
599 #endif
601 if (!process_startup &&
602 command_line.HasSwitch(switches::kDumpBrowserHistograms)) {
603 // Only handle --dump-browser-histograms from a rendezvous. In this case, do
604 // not open a new browser window even if no output file was given.
605 base::FilePath output_file(
606 command_line.GetSwitchValuePath(switches::kDumpBrowserHistograms));
607 if (!output_file.empty()) {
608 BrowserThread::PostBlockingPoolTask(
609 FROM_HERE,
610 base::Bind(&DumpBrowserHistograms, output_file));
612 silent_launch = true;
615 // If --no-startup-window is specified and Chrome is already running then do
616 // not open a new window.
617 if (!process_startup && command_line.HasSwitch(switches::kNoStartupWindow))
618 silent_launch = true;
620 // If we don't want to launch a new browser window or tab we are done here.
621 if (silent_launch)
622 return true;
624 VLOG(2) << "ProcessCmdLineImpl: PLACE 4.A";
625 if (command_line.HasSwitch(extensions::switches::kLoadApps) &&
626 !IncognitoModePrefs::ShouldLaunchIncognito(
627 command_line, last_used_profile->GetPrefs())) {
628 if (!ProcessLoadApps(command_line, cur_dir, last_used_profile))
629 return false;
631 // Return early here to avoid opening a browser window.
632 // The exception is when there are no browser windows, since we don't want
633 // chrome to shut down.
634 // TODO(jackhou): Do this properly once keep-alive is handled by the
635 // background page of apps. Tracked at http://crbug.com/175381
636 if (chrome::GetTotalBrowserCountForProfile(last_used_profile) != 0)
637 return true;
640 VLOG(2) << "ProcessCmdLineImpl: PLACE 4.B";
641 // Check for --load-and-launch-app.
642 if (command_line.HasSwitch(apps::kLoadAndLaunchApp) &&
643 !IncognitoModePrefs::ShouldLaunchIncognito(
644 command_line, last_used_profile->GetPrefs())) {
645 base::CommandLine::StringType path =
646 command_line.GetSwitchValueNative(apps::kLoadAndLaunchApp);
648 if (!apps::AppLoadService::Get(last_used_profile)->LoadAndLaunch(
649 base::FilePath(path), command_line, cur_dir)) {
650 return false;
653 // Return early here since we don't want to open a browser window.
654 // The exception is when there are no browser windows, since we don't want
655 // chrome to shut down.
656 // TODO(jackhou): Do this properly once keep-alive is handled by the
657 // background page of apps. Tracked at http://crbug.com/175381
658 if (chrome::GetTotalBrowserCountForProfile(last_used_profile) != 0)
659 return true;
662 #if defined(OS_WIN)
663 // Log whether this process was a result of an action in the Windows Jumplist.
664 if (command_line.HasSwitch(switches::kWinJumplistAction)) {
665 jumplist::LogJumplistActionFromSwitchValue(
666 command_line.GetSwitchValueASCII(switches::kWinJumplistAction));
668 #endif
670 VLOG(2) << "ProcessCmdLineImpl: PLACE 5";
671 chrome::startup::IsProcessStartup is_process_startup = process_startup ?
672 chrome::startup::IS_PROCESS_STARTUP :
673 chrome::startup::IS_NOT_PROCESS_STARTUP;
674 chrome::startup::IsFirstRun is_first_run = first_run::IsChromeFirstRun() ?
675 chrome::startup::IS_FIRST_RUN : chrome::startup::IS_NOT_FIRST_RUN;
676 // |last_opened_profiles| will be empty in the following circumstances:
677 // - This is the first launch. |last_used_profile| is the initial profile.
678 // - The user exited the browser by closing all windows for all
679 // profiles. |last_used_profile| is the profile which owned the last open
680 // window.
681 // - Only incognito windows were open when the browser exited.
682 // |last_used_profile| is the last used incognito profile. Restoring it will
683 // create a browser window for the corresponding original profile.
684 if (last_opened_profiles.empty()) {
685 VLOG(2) << "ProcessCmdLineImpl: PLACE 6.A";
686 // If the last used profile is locked or was a guest, show the user manager.
687 if (switches::IsNewAvatarMenu()) {
688 ProfileInfoCache& profile_info =
689 g_browser_process->profile_manager()->GetProfileInfoCache();
690 size_t profile_index = profile_info.GetIndexOfProfileWithPath(
691 last_used_profile->GetPath());
692 bool signin_required = profile_index != std::string::npos &&
693 profile_info.ProfileIsSigninRequiredAtIndex(profile_index);
695 // Guest, system or locked profiles cannot be re-opened on startup. The
696 // only exception is if there's already a Guest window open in a separate
697 // process (for example, launching a new browser after clicking on a
698 // downloaded file in Guest mode).
699 bool guest_or_system = last_used_profile->IsGuestSession() ||
700 last_used_profile->IsSystemProfile();
701 bool has_guest_browsers = guest_or_system &&
702 chrome::GetTotalBrowserCountForProfile(
703 last_used_profile->GetOffTheRecordProfile()) > 0;
704 if (signin_required || (guest_or_system && !has_guest_browsers)) {
705 profiles::UserManagerProfileSelected action =
706 command_line.HasSwitch(switches::kShowAppList) ?
707 profiles::USER_MANAGER_SELECT_PROFILE_APP_LAUNCHER :
708 profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION;
709 UserManager::Show(
710 base::FilePath(), profiles::USER_MANAGER_NO_TUTORIAL, action);
711 return true;
715 VLOG(2) << "ProcessCmdLineImpl: PLACE 7.A";
716 Profile* profile_to_open = last_used_profile->IsGuestSession() ?
717 last_used_profile->GetOffTheRecordProfile() : last_used_profile;
719 VLOG(2) << "ProcessCmdLineImpl: PLACE 8.A";
720 if (!browser_creator->LaunchBrowser(command_line, profile_to_open,
721 cur_dir, is_process_startup,
722 is_first_run)) {
723 return false;
725 } else {
726 VLOG(2) << "ProcessCmdLineImpl: PLACE 6.B";
727 // Guest profiles should not be reopened on startup. This can happen if
728 // the last used profile was a Guest, but other profiles were also open
729 // when Chrome was closed. In this case, pick a different open profile
730 // to be the active one, since the Guest profile is never added to the list
731 // of open profiles.
732 if (switches::IsNewAvatarMenu() && last_used_profile->IsGuestSession()) {
733 DCHECK(!last_opened_profiles[0]->IsGuestSession());
734 last_used_profile = last_opened_profiles[0];
737 // Launch the last used profile with the full command line, and the other
738 // opened profiles without the URLs to launch.
739 base::CommandLine command_line_without_urls(command_line.GetProgram());
740 const base::CommandLine::SwitchMap& switches = command_line.GetSwitches();
741 for (base::CommandLine::SwitchMap::const_iterator switch_it =
742 switches.begin();
743 switch_it != switches.end(); ++switch_it) {
744 command_line_without_urls.AppendSwitchNative(switch_it->first,
745 switch_it->second);
747 VLOG(2) << "ProcessCmdLineImpl: PLACE 7.B";
748 // Launch the profiles in the order they became active.
749 for (Profiles::const_iterator it = last_opened_profiles.begin();
750 it != last_opened_profiles.end(); ++it) {
751 DCHECK(!(*it)->IsGuestSession());
752 // Don't launch additional profiles which would only open a new tab
753 // page. When restarting after an update, all profiles will reopen last
754 // open pages.
755 SessionStartupPref startup_pref =
756 GetSessionStartupPref(command_line, *it);
757 if (*it != last_used_profile &&
758 startup_pref.type == SessionStartupPref::DEFAULT &&
759 !HasPendingUncleanExit(*it))
760 continue;
762 if (!browser_creator->LaunchBrowser((*it == last_used_profile) ?
763 command_line : command_line_without_urls, *it, cur_dir,
764 is_process_startup, is_first_run))
765 return false;
766 // We've launched at least one browser.
767 is_process_startup = chrome::startup::IS_NOT_PROCESS_STARTUP;
769 VLOG(2) << "ProcessCmdLineImpl: PLACE 8.B";
770 // This must be done after all profiles have been launched so the observer
771 // knows about all profiles to wait for before activating this one.
772 profile_launch_observer.Get().set_profile_to_activate(last_used_profile);
774 VLOG(2) << "ProcessCmdLineImpl: END";
775 return true;
778 // static
779 bool StartupBrowserCreator::ProcessLoadApps(
780 const base::CommandLine& command_line,
781 const base::FilePath& cur_dir,
782 Profile* profile) {
783 base::CommandLine::StringType path_list =
784 command_line.GetSwitchValueNative(extensions::switches::kLoadApps);
786 base::StringTokenizerT<base::CommandLine::StringType,
787 base::CommandLine::StringType::const_iterator>
788 tokenizer(path_list, FILE_PATH_LITERAL(","));
790 if (!tokenizer.GetNext())
791 return false;
793 base::FilePath app_absolute_dir =
794 base::MakeAbsoluteFilePath(base::FilePath(tokenizer.token()));
795 if (!apps::AppLoadService::Get(profile)->LoadAndLaunch(
796 app_absolute_dir, command_line, cur_dir)) {
797 return false;
800 while (tokenizer.GetNext()) {
801 app_absolute_dir =
802 base::MakeAbsoluteFilePath(base::FilePath(tokenizer.token()));
804 if (!apps::AppLoadService::Get(profile)->Load(app_absolute_dir)) {
805 return false;
809 return true;
812 // static
813 void StartupBrowserCreator::ProcessCommandLineOnProfileCreated(
814 const base::CommandLine& command_line,
815 const base::FilePath& cur_dir,
816 Profile* profile,
817 Profile::CreateStatus status) {
818 if (status != Profile::CREATE_STATUS_INITIALIZED)
819 return;
820 ProcessCmdLineImpl(command_line, cur_dir, false, profile, Profiles(), NULL);
823 // static
824 void StartupBrowserCreator::ProcessCommandLineAlreadyRunning(
825 const base::CommandLine& command_line,
826 const base::FilePath& cur_dir,
827 const base::FilePath& profile_path) {
828 ProfileManager* profile_manager = g_browser_process->profile_manager();
829 Profile* profile = profile_manager->GetProfileByPath(profile_path);
831 // The profile isn't loaded yet and so needs to be loaded asynchronously.
832 if (!profile) {
833 profile_manager->CreateProfileAsync(profile_path,
834 base::Bind(&StartupBrowserCreator::ProcessCommandLineOnProfileCreated,
835 command_line, cur_dir), base::string16(), base::string16(),
836 std::string());
837 return;
840 ProcessCmdLineImpl(command_line, cur_dir, false, profile, Profiles(), NULL);
843 // static
844 bool StartupBrowserCreator::ActivatedProfile() {
845 return profile_launch_observer.Get().activated_profile();
848 bool HasPendingUncleanExit(Profile* profile) {
849 return profile->GetLastSessionExitType() == Profile::EXIT_CRASHED &&
850 !profile_launch_observer.Get().HasBeenLaunched(profile);
853 base::FilePath GetStartupProfilePath(const base::FilePath& user_data_dir,
854 const base::CommandLine& command_line) {
855 if (command_line.HasSwitch(switches::kProfileDirectory)) {
856 return user_data_dir.Append(
857 command_line.GetSwitchValuePath(switches::kProfileDirectory));
860 // If we are showing the app list then chrome isn't shown so load the app
861 // list's profile rather than chrome's.
862 if (command_line.HasSwitch(switches::kShowAppList)) {
863 return AppListService::Get(chrome::HOST_DESKTOP_TYPE_NATIVE)->
864 GetProfilePath(user_data_dir);
867 return g_browser_process->profile_manager()->GetLastUsedProfileDir(
868 user_data_dir);