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