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