1 // Copyright (c) 2011 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/browser_init.h" 6 7 #include <algorithm> // For max(). 8 9 #include "base/compiler_specific.h" 10 #include "base/environment.h" 11 #include "base/event_recorder.h" 12 #include "base/file_path.h" 13 #include "base/memory/scoped_ptr.h" 14 #include "base/metrics/histogram.h" 15 #include "base/path_service.h" 16 #include "base/string_number_conversions.h" 17 #include "base/string_split.h" 18 #include "base/threading/thread_restrictions.h" 19 #include "base/utf_string_conversions.h" 20 #include "chrome/browser/automation/automation_provider.h" 21 #include "chrome/browser/automation/automation_provider_list.h" 22 #include "chrome/browser/automation/chrome_frame_automation_provider.h" 23 #include "chrome/browser/automation/testing_automation_provider.h" 24 #include "chrome/browser/browser_process.h" 25 #include "chrome/browser/defaults.h" 26 #include "chrome/browser/extensions/extension_creator.h" 27 #include "chrome/browser/extensions/extension_service.h" 28 #include "chrome/browser/extensions/pack_extension_job.h" 29 #include "chrome/browser/first_run/first_run.h" 30 #include "chrome/browser/net/predictor_api.h" 31 #include "chrome/browser/net/url_fixer_upper.h" 32 #include "chrome/browser/notifications/desktop_notification_service.h" 33 #include "chrome/browser/platform_util.h" 34 #include "chrome/browser/prefs/pref_service.h" 35 #include "chrome/browser/prefs/session_startup_pref.h" 36 #include "chrome/browser/printing/cloud_print/cloud_print_proxy_service.h" 37 #include "chrome/browser/printing/print_dialog_cloud.h" 38 #include "chrome/browser/profiles/profile.h" 39 #include "chrome/browser/search_engines/template_url.h" 40 #include "chrome/browser/search_engines/template_url_model.h" 41 #include "chrome/browser/sessions/session_restore.h" 42 #include "chrome/browser/sessions/session_service.h" 43 #include "chrome/browser/shell_integration.h" 44 #include "chrome/browser/tab_contents/link_infobar_delegate.h" 45 #include "chrome/browser/tab_contents/simple_alert_infobar_delegate.h" 46 #include "chrome/browser/tabs/pinned_tab_codec.h" 47 #include "chrome/browser/tabs/tab_strip_model.h" 48 #include "chrome/browser/ui/browser_list.h" 49 #include "chrome/browser/ui/browser_navigator.h" 50 #include "chrome/browser/ui/browser_window.h" 51 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" 52 #include "chrome/common/chrome_constants.h" 53 #include "chrome/common/chrome_paths.h" 54 #include "chrome/common/chrome_switches.h" 55 #include "chrome/common/extensions/extension_constants.h" 56 #include "chrome/common/pref_names.h" 57 #include "chrome/common/url_constants.h" 58 #include "chrome/installer/util/browser_distribution.h" 59 #include "content/browser/browser_thread.h" 60 #include "content/browser/child_process_security_policy.h" 61 #include "content/browser/renderer_host/render_process_host.h" 62 #include "content/browser/tab_contents/navigation_controller.h" 63 #include "content/browser/tab_contents/tab_contents.h" 64 #include "content/browser/tab_contents/tab_contents_view.h" 65 #include "content/common/result_codes.h" 66 #include "grit/chromium_strings.h" 67 #include "grit/generated_resources.h" 68 #include "grit/locale_settings.h" 69 #include "grit/theme_resources.h" 70 #include "net/base/net_util.h" 71 #include "net/url_request/url_request.h" 72 #include "ui/base/l10n/l10n_util.h" 73 #include "ui/base/resource/resource_bundle.h" 74 #include "webkit/glue/webkit_glue.h" 75 76 #if defined(OS_MACOSX) 77 #include "chrome/browser/ui/cocoa/keystone_infobar.h" 78 #endif 79 80 #if defined(TOOLKIT_USES_GTK) 81 #include "chrome/browser/ui/gtk/gtk_util.h" 82 #endif 83 84 #if defined(OS_CHROMEOS) 85 #include "chrome/browser/chromeos/cros/cros_library.h" 86 #include "chrome/browser/chromeos/cros/mount_library.h" 87 #include "chrome/browser/chromeos/cros/network_library.h" 88 #include "chrome/browser/chromeos/customization_document.h" 89 #include "chrome/browser/chromeos/enterprise_extension_observer.h" 90 #include "chrome/browser/chromeos/gview_request_interceptor.h" 91 #include "chrome/browser/chromeos/low_battery_observer.h" 92 #include "chrome/browser/chromeos/network_message_observer.h" 93 #include "chrome/browser/chromeos/network_state_notifier.h" 94 #include "chrome/browser/chromeos/sms_observer.h" 95 #include "chrome/browser/chromeos/update_observer.h" 96 #include "chrome/browser/chromeos/wm_message_listener.h" 97 #include "chrome/browser/chromeos/wm_overview_controller.h" 98 #include "chrome/browser/ui/webui/mediaplayer_ui.h" 99 #endif 100 101 #if defined(HAVE_XINPUT2) 102 #include "views/focus/accelerator_handler.h" 103 #endif 104 105 namespace { 106 107 // SetAsDefaultBrowserTask ---------------------------------------------------- 108 109 class SetAsDefaultBrowserTask : public Task { 110 public: 111 SetAsDefaultBrowserTask(); 112 virtual ~SetAsDefaultBrowserTask(); 113 114 private: 115 virtual void Run(); 116 117 DISALLOW_COPY_AND_ASSIGN(SetAsDefaultBrowserTask); 118 }; 119 120 SetAsDefaultBrowserTask::SetAsDefaultBrowserTask() { 121 } 122 123 SetAsDefaultBrowserTask::~SetAsDefaultBrowserTask() { 124 } 125 126 void SetAsDefaultBrowserTask::Run() { 127 ShellIntegration::SetAsDefaultBrowser(); 128 } 129 130 131 // DefaultBrowserInfoBarDelegate ---------------------------------------------- 132 133 // The delegate for the infobar shown when Chrome is not the default browser. 134 class DefaultBrowserInfoBarDelegate : public ConfirmInfoBarDelegate { 135 public: 136 explicit DefaultBrowserInfoBarDelegate(TabContents* contents); 137 138 private: 139 virtual ~DefaultBrowserInfoBarDelegate(); 140 141 void AllowExpiry() { should_expire_ = true; } 142 143 // ConfirmInfoBarDelegate: 144 virtual bool ShouldExpire( 145 const NavigationController::LoadCommittedDetails& details) const OVERRIDE; 146 virtual void InfoBarClosed() OVERRIDE; 147 virtual SkBitmap* GetIcon() const OVERRIDE; 148 virtual string16 GetMessageText() const OVERRIDE; 149 virtual string16 GetButtonLabel(InfoBarButton button) const OVERRIDE; 150 virtual bool NeedElevation(InfoBarButton button) const OVERRIDE; 151 virtual bool Accept() OVERRIDE; 152 virtual bool Cancel() OVERRIDE; 153 154 // The Profile that we restore sessions from. 155 Profile* profile_; 156 157 // Whether the user clicked one of the buttons. 158 bool action_taken_; 159 160 // Whether the info-bar should be dismissed on the next navigation. 161 bool should_expire_; 162 163 // Used to delay the expiration of the info-bar. 164 ScopedRunnableMethodFactory<DefaultBrowserInfoBarDelegate> method_factory_; 165 166 DISALLOW_COPY_AND_ASSIGN(DefaultBrowserInfoBarDelegate); 167 }; 168 169 DefaultBrowserInfoBarDelegate::DefaultBrowserInfoBarDelegate( 170 TabContents* contents) 171 : ConfirmInfoBarDelegate(contents), 172 profile_(contents->profile()), 173 action_taken_(false), 174 should_expire_(false), 175 ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { 176 // We want the info-bar to stick-around for few seconds and then be hidden 177 // on the next navigation after that. 178 MessageLoop::current()->PostDelayedTask(FROM_HERE, 179 method_factory_.NewRunnableMethod( 180 &DefaultBrowserInfoBarDelegate::AllowExpiry), 8000); // 8 seconds. 181 } 182 183 DefaultBrowserInfoBarDelegate::~DefaultBrowserInfoBarDelegate() { 184 } 185 186 bool DefaultBrowserInfoBarDelegate::ShouldExpire( 187 const NavigationController::LoadCommittedDetails& details) const { 188 return should_expire_; 189 } 190 191 void DefaultBrowserInfoBarDelegate::InfoBarClosed() { 192 if (!action_taken_) 193 UMA_HISTOGRAM_COUNTS("DefaultBrowserWarning.Ignored", 1); 194 delete this; 195 } 196 197 SkBitmap* DefaultBrowserInfoBarDelegate::GetIcon() const { 198 return ResourceBundle::GetSharedInstance().GetBitmapNamed( 199 IDR_PRODUCT_ICON_32); 200 } 201 202 string16 DefaultBrowserInfoBarDelegate::GetMessageText() const { 203 return l10n_util::GetStringUTF16(IDS_DEFAULT_BROWSER_INFOBAR_SHORT_TEXT); 204 } 205 206 string16 DefaultBrowserInfoBarDelegate::GetButtonLabel( 207 InfoBarButton button) const { 208 return l10n_util::GetStringUTF16((button == BUTTON_OK) ? 209 IDS_SET_AS_DEFAULT_INFOBAR_BUTTON_LABEL : 210 IDS_DONT_ASK_AGAIN_INFOBAR_BUTTON_LABEL); 211 } 212 213 bool DefaultBrowserInfoBarDelegate::NeedElevation(InfoBarButton button) const { 214 return button == BUTTON_OK; 215 } 216 217 bool DefaultBrowserInfoBarDelegate::Accept() { 218 action_taken_ = true; 219 UMA_HISTOGRAM_COUNTS("DefaultBrowserWarning.SetAsDefault", 1); 220 g_browser_process->file_thread()->message_loop()->PostTask(FROM_HERE, 221 new SetAsDefaultBrowserTask()); 222 return true; 223 } 224 225 bool DefaultBrowserInfoBarDelegate::Cancel() { 226 action_taken_ = true; 227 UMA_HISTOGRAM_COUNTS("DefaultBrowserWarning.DontSetAsDefault", 1); 228 // User clicked "Don't ask me again", remember that. 229 profile_->GetPrefs()->SetBoolean(prefs::kCheckDefaultBrowser, false); 230 return true; 231 } 232 233 234 // NotifyNotDefaultBrowserTask ------------------------------------------------ 235 236 class NotifyNotDefaultBrowserTask : public Task { 237 public: 238 NotifyNotDefaultBrowserTask(); 239 virtual ~NotifyNotDefaultBrowserTask(); 240 241 private: 242 virtual void Run(); 243 244 DISALLOW_COPY_AND_ASSIGN(NotifyNotDefaultBrowserTask); 245 }; 246 247 NotifyNotDefaultBrowserTask::NotifyNotDefaultBrowserTask() { 248 } 249 250 NotifyNotDefaultBrowserTask::~NotifyNotDefaultBrowserTask() { 251 } 252 253 void NotifyNotDefaultBrowserTask::Run() { 254 Browser* browser = BrowserList::GetLastActive(); 255 if (!browser) 256 return; // Reached during ui tests. 257 // Don't show the info-bar if there are already info-bars showing. 258 // In ChromeBot tests, there might be a race. This line appears to get 259 // called during shutdown and |tab| can be NULL. 260 TabContents* tab = browser->GetSelectedTabContents(); 261 if (!tab || tab->infobar_count() > 0) 262 return; 263 tab->AddInfoBar(new DefaultBrowserInfoBarDelegate(tab)); 264 } 265 266 267 // CheckDefaultBrowserTask ---------------------------------------------------- 268 269 class CheckDefaultBrowserTask : public Task { 270 public: 271 CheckDefaultBrowserTask(); 272 virtual ~CheckDefaultBrowserTask(); 273 274 private: 275 virtual void Run(); 276 277 DISALLOW_COPY_AND_ASSIGN(CheckDefaultBrowserTask); 278 }; 279 280 CheckDefaultBrowserTask::CheckDefaultBrowserTask() { 281 } 282 283 CheckDefaultBrowserTask::~CheckDefaultBrowserTask() { 284 } 285 286 void CheckDefaultBrowserTask::Run() { 287 if (ShellIntegration::IsDefaultBrowser() || 288 !platform_util::CanSetAsDefaultBrowser()) { 289 return; 290 } 291 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 292 new NotifyNotDefaultBrowserTask()); 293 } 294 295 296 // SessionCrashedInfoBarDelegate ---------------------------------------------- 297 298 // A delegate for the InfoBar shown when the previous session has crashed. 299 class SessionCrashedInfoBarDelegate : public ConfirmInfoBarDelegate { 300 public: 301 explicit SessionCrashedInfoBarDelegate(TabContents* contents); 302 303 private: 304 virtual ~SessionCrashedInfoBarDelegate(); 305 306 // ConfirmInfoBarDelegate: 307 virtual void InfoBarClosed() OVERRIDE; 308 virtual SkBitmap* GetIcon() const OVERRIDE; 309 virtual string16 GetMessageText() const OVERRIDE; 310 virtual int GetButtons() const OVERRIDE; 311 virtual string16 GetButtonLabel(InfoBarButton button) const OVERRIDE; 312 virtual bool Accept() OVERRIDE; 313 314 // The Profile that we restore sessions from. 315 Profile* profile_; 316 317 DISALLOW_COPY_AND_ASSIGN(SessionCrashedInfoBarDelegate); 318 }; 319 320 SessionCrashedInfoBarDelegate::SessionCrashedInfoBarDelegate( 321 TabContents* contents) 322 : ConfirmInfoBarDelegate(contents), 323 profile_(contents->profile()) { 324 } 325 326 SessionCrashedInfoBarDelegate::~SessionCrashedInfoBarDelegate() { 327 } 328 329 void SessionCrashedInfoBarDelegate::InfoBarClosed() { 330 delete this; 331 } 332 333 SkBitmap* SessionCrashedInfoBarDelegate::GetIcon() const { 334 return ResourceBundle::GetSharedInstance().GetBitmapNamed( 335 IDR_INFOBAR_RESTORE_SESSION); 336 } 337 338 string16 SessionCrashedInfoBarDelegate::GetMessageText() const { 339 return l10n_util::GetStringUTF16(IDS_SESSION_CRASHED_VIEW_MESSAGE); 340 } 341 342 int SessionCrashedInfoBarDelegate::GetButtons() const { 343 return BUTTON_OK; 344 } 345 346 string16 SessionCrashedInfoBarDelegate::GetButtonLabel( 347 InfoBarButton button) const { 348 DCHECK_EQ(BUTTON_OK, button); 349 return l10n_util::GetStringUTF16(IDS_SESSION_CRASHED_VIEW_RESTORE_BUTTON); 350 } 351 352 bool SessionCrashedInfoBarDelegate::Accept() { 353 SessionRestore::RestoreSession(profile_, NULL, true, false, 354 std::vector<GURL>()); 355 return true; 356 } 357 358 359 // Utility functions ---------------------------------------------------------- 360 361 SessionStartupPref GetSessionStartupPref(const CommandLine& command_line, 362 Profile* profile) { 363 SessionStartupPref pref = SessionStartupPref::GetStartupPref(profile); 364 if (command_line.HasSwitch(switches::kRestoreLastSession)) 365 pref.type = SessionStartupPref::LAST; 366 if (command_line.HasSwitch(switches::kIncognito) && 367 pref.type == SessionStartupPref::LAST && 368 profile->GetPrefs()->GetBoolean(prefs::kIncognitoEnabled)) { 369 // We don't store session information when incognito. If the user has 370 // chosen to restore last session and launched incognito, fallback to 371 // default launch behavior. 372 pref.type = SessionStartupPref::DEFAULT; 373 } 374 return pref; 375 } 376 377 enum LaunchMode { 378 LM_TO_BE_DECIDED = 0, // Possibly direct launch or via a shortcut. 379 LM_AS_WEBAPP, // Launched as a installed web application. 380 LM_WITH_URLS, // Launched with urls in the cmd line. 381 LM_SHORTCUT_NONE, // Not launched from a shortcut. 382 LM_SHORTCUT_NONAME, // Launched from shortcut but no name available. 383 LM_SHORTCUT_UNKNOWN, // Launched from user-defined shortcut. 384 LM_SHORTCUT_QUICKLAUNCH, // Launched from the quick launch bar. 385 LM_SHORTCUT_DESKTOP, // Launched from a desktop shortcut. 386 LM_SHORTCUT_STARTMENU, // Launched from start menu. 387 LM_LINUX_MAC_BEOS // Other OS buckets start here. 388 }; 389 390 #if defined(OS_WIN) 391 // Undocumented flag in the startup info structure tells us what shortcut was 392 // used to launch the browser. See http://www.catch22.net/tuts/undoc01 for 393 // more information. Confirmed to work on XP, Vista and Win7. 394 LaunchMode GetLaunchShortcutKind() { 395 STARTUPINFOW si = { sizeof(si) }; 396 GetStartupInfoW(&si); 397 if (si.dwFlags & 0x800) { 398 if (!si.lpTitle) 399 return LM_SHORTCUT_NONAME; 400 std::wstring shortcut(si.lpTitle); 401 // The windows quick launch path is not localized. 402 if (shortcut.find(L"\\Quick Launch\\") != std::wstring::npos) 403 return LM_SHORTCUT_QUICKLAUNCH; 404 scoped_ptr<base::Environment> env(base::Environment::Create()); 405 std::string appdata_path; 406 env->GetVar("USERPROFILE", &appdata_path); 407 if (!appdata_path.empty() && 408 shortcut.find(ASCIIToWide(appdata_path)) != std::wstring::npos) 409 return LM_SHORTCUT_DESKTOP; 410 return LM_SHORTCUT_UNKNOWN; 411 } 412 return LM_SHORTCUT_NONE; 413 } 414 #else 415 // TODO(cpu): Port to other platforms. 416 LaunchMode GetLaunchShortcutKind() { 417 return LM_LINUX_MAC_BEOS; 418 } 419 #endif 420 421 // Log in a histogram the frequency of launching by the different methods. See 422 // LaunchMode enum for the actual values of the buckets. 423 void RecordLaunchModeHistogram(LaunchMode mode) { 424 int bucket = (mode == LM_TO_BE_DECIDED) ? GetLaunchShortcutKind() : mode; 425 UMA_HISTOGRAM_COUNTS_100("Launch.Modes", bucket); 426 } 427 428 static bool in_startup = false; 429 430 GURL GetWelcomePageURL() { 431 std::string welcome_url = l10n_util::GetStringUTF8(IDS_WELCOME_PAGE_URL); 432 return GURL(welcome_url); 433 } 434 435 void UrlsToTabs(const std::vector<GURL>& urls, 436 std::vector<BrowserInit::LaunchWithProfile::Tab>* tabs) { 437 for (size_t i = 0; i < urls.size(); ++i) { 438 BrowserInit::LaunchWithProfile::Tab tab; 439 tab.is_pinned = false; 440 tab.url = urls[i]; 441 tabs->push_back(tab); 442 } 443 } 444 445 // Return true if the command line option --app-id is used. Set 446 // |out_extension| to the app to open, and |out_launch_container| 447 // to the type of window into which the app should be open. 448 bool GetAppLaunchContainer( 449 Profile* profile, 450 const std::string& app_id, 451 const Extension** out_extension, 452 extension_misc::LaunchContainer* out_launch_container) { 453 454 ExtensionService* extensions_service = profile->GetExtensionService(); 455 const Extension* extension = 456 extensions_service->GetExtensionById(app_id, false); 457 458 // The extension with id |app_id| may have been uninstalled. 459 if (!extension) 460 return false; 461 462 // Look at preferences to find the right launch container. If no 463 // preference is set, launch as a window. 464 extension_misc::LaunchContainer launch_container = 465 extensions_service->extension_prefs()->GetLaunchContainer( 466 extension, ExtensionPrefs::LAUNCH_WINDOW); 467 468 *out_extension = extension; 469 *out_launch_container = launch_container; 470 return true; 471 } 472 473 void RecordCmdLineAppHistogram() { 474 UMA_HISTOGRAM_ENUMERATION(extension_misc::kAppLaunchHistogram, 475 extension_misc::APP_LAUNCH_CMD_LINE_APP, 476 extension_misc::APP_LAUNCH_BUCKET_BOUNDARY); 477 } 478 479 void RecordAppLaunches( 480 Profile* profile, 481 const std::vector<GURL>& cmd_line_urls, 482 const std::vector<BrowserInit::LaunchWithProfile::Tab>& autolaunch_tabs) { 483 ExtensionService* extension_service = profile->GetExtensionService(); 484 DCHECK(extension_service); 485 for (size_t i = 0; i < cmd_line_urls.size(); ++i) { 486 if (extension_service->IsInstalledApp(cmd_line_urls.at(i))) { 487 UMA_HISTOGRAM_ENUMERATION(extension_misc::kAppLaunchHistogram, 488 extension_misc::APP_LAUNCH_CMD_LINE_URL, 489 extension_misc::APP_LAUNCH_BUCKET_BOUNDARY); 490 } 491 } 492 for (size_t i = 0; i < autolaunch_tabs.size(); ++i) { 493 if (extension_service->IsInstalledApp(autolaunch_tabs.at(i).url)) { 494 UMA_HISTOGRAM_ENUMERATION(extension_misc::kAppLaunchHistogram, 495 extension_misc::APP_LAUNCH_AUTOLAUNCH, 496 extension_misc::APP_LAUNCH_BUCKET_BOUNDARY); 497 } 498 } 499 } 500 501 } // namespace 502 503 504 // BrowserInit ---------------------------------------------------------------- 505 506 BrowserInit::BrowserInit() {} 507 508 BrowserInit::~BrowserInit() {} 509 510 void BrowserInit::AddFirstRunTab(const GURL& url) { 511 first_run_tabs_.push_back(url); 512 } 513 514 // static 515 bool BrowserInit::InProcessStartup() { 516 return in_startup; 517 } 518 519 bool BrowserInit::LaunchBrowser(const CommandLine& command_line, 520 Profile* profile, 521 const FilePath& cur_dir, 522 bool process_startup, 523 int* return_code) { 524 in_startup = process_startup; 525 DCHECK(profile); 526 #if defined(OS_CHROMEOS) 527 if (process_startup) { 528 // NetworkStateNotifier has to be initialized before Launching browser 529 // because the page load can happen in parallel to this UI thread 530 // and IO thread may access the NetworkStateNotifier. 531 chromeos::CrosLibrary::Get()->GetNetworkLibrary() 532 ->AddNetworkManagerObserver( 533 chromeos::NetworkStateNotifier::GetInstance()); 534 } 535 #endif 536 537 // Continue with the incognito profile from here on if --incognito 538 if (command_line.HasSwitch(switches::kIncognito) && 539 profile->GetPrefs()->GetBoolean(prefs::kIncognitoEnabled)) { 540 profile = profile->GetOffTheRecordProfile(); 541 } 542 543 BrowserInit::LaunchWithProfile lwp(cur_dir, command_line, this); 544 std::vector<GURL> urls_to_launch = BrowserInit::GetURLsFromCommandLine( 545 command_line, cur_dir, profile); 546 bool launched = lwp.Launch(profile, urls_to_launch, process_startup); 547 in_startup = false; 548 549 if (!launched) { 550 LOG(ERROR) << "launch error"; 551 if (return_code) 552 *return_code = ResultCodes::INVALID_CMDLINE_URL; 553 return false; 554 } 555 556 #if defined(OS_CHROMEOS) 557 // Initialize Chrome OS preferences like touch pad sensitivity. For the 558 // preferences to work in the guest mode, the initialization has to be 559 // done after |profile| is switched to the incognito profile (which 560 // is actually GuestSessionProfile in the guest mode). See the 561 // GetOffTheRecordProfile() call above. 562 profile->InitChromeOSPreferences(); 563 564 // Create the WmMessageListener so that it can listen for messages regardless 565 // of what window has focus. 566 chromeos::WmMessageListener::GetInstance(); 567 568 // Create the WmOverviewController so it can register with the listener. 569 chromeos::WmOverviewController::GetInstance(); 570 571 // Install the GView request interceptor that will redirect requests 572 // of compatible documents (PDF, etc) to the GView document viewer. 573 const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess(); 574 if (parsed_command_line.HasSwitch(switches::kEnableGView)) { 575 chromeos::GViewRequestInterceptor::GetInstance(); 576 } 577 if (process_startup) { 578 // This observer is a singleton. It is never deleted but the pointer is kept 579 // in a static so that it isn't reported as a leak. 580 static chromeos::LowBatteryObserver* low_battery_observer = 581 new chromeos::LowBatteryObserver(profile); 582 chromeos::CrosLibrary::Get()->GetPowerLibrary()->AddObserver( 583 low_battery_observer); 584 585 static chromeos::UpdateObserver* update_observer = 586 new chromeos::UpdateObserver(profile); 587 chromeos::CrosLibrary::Get()->GetUpdateLibrary()->AddObserver( 588 update_observer); 589 590 static chromeos::NetworkMessageObserver* network_message_observer = 591 new chromeos::NetworkMessageObserver(profile); 592 chromeos::CrosLibrary::Get()->GetNetworkLibrary() 593 ->AddNetworkManagerObserver(network_message_observer); 594 chromeos::CrosLibrary::Get()->GetNetworkLibrary() 595 ->AddCellularDataPlanObserver(network_message_observer); 596 chromeos::CrosLibrary::Get()->GetNetworkLibrary() 597 ->AddUserActionObserver(network_message_observer); 598 599 static chromeos::SmsObserver* sms_observer = 600 new chromeos::SmsObserver(profile); 601 chromeos::CrosLibrary::Get()->GetNetworkLibrary() 602 ->AddNetworkManagerObserver(sms_observer); 603 604 profile->SetupChromeOSEnterpriseExtensionObserver(); 605 } 606 #endif 607 return true; 608 } 609 610 611 // BrowserInit::LaunchWithProfile::Tab ---------------------------------------- 612 613 BrowserInit::LaunchWithProfile::Tab::Tab() : is_app(false), is_pinned(true) {} 614 615 BrowserInit::LaunchWithProfile::Tab::~Tab() {} 616 617 618 // BrowserInit::LaunchWithProfile --------------------------------------------- 619 620 BrowserInit::LaunchWithProfile::LaunchWithProfile( 621 const FilePath& cur_dir, 622 const CommandLine& command_line) 623 : cur_dir_(cur_dir), 624 command_line_(command_line), 625 profile_(NULL), 626 browser_init_(NULL) { 627 } 628 629 BrowserInit::LaunchWithProfile::LaunchWithProfile( 630 const FilePath& cur_dir, 631 const CommandLine& command_line, 632 BrowserInit* browser_init) 633 : cur_dir_(cur_dir), 634 command_line_(command_line), 635 profile_(NULL), 636 browser_init_(browser_init) { 637 } 638 639 BrowserInit::LaunchWithProfile::~LaunchWithProfile() { 640 } 641 642 bool BrowserInit::LaunchWithProfile::Launch( 643 Profile* profile, 644 const std::vector<GURL>& urls_to_open, 645 bool process_startup) { 646 DCHECK(profile); 647 profile_ = profile; 648 649 if (command_line_.HasSwitch(switches::kDnsLogDetails)) 650 chrome_browser_net::EnablePredictorDetailedLog(true); 651 if (command_line_.HasSwitch(switches::kDnsPrefetchDisable)) 652 chrome_browser_net::EnablePredictor(false); 653 654 if (command_line_.HasSwitch(switches::kDumpHistogramsOnExit)) 655 base::StatisticsRecorder::set_dump_on_exit(true); 656 657 if (command_line_.HasSwitch(switches::kRemoteShellPort)) { 658 std::string port_str = 659 command_line_.GetSwitchValueASCII(switches::kRemoteShellPort); 660 int64 port; 661 if (base::StringToInt64(port_str, &port) && port > 0 && port < 65535) { 662 g_browser_process->InitDevToolsLegacyProtocolHandler( 663 static_cast<int>(port)); 664 } else { 665 DLOG(WARNING) << "Invalid remote shell port number " << port; 666 } 667 } else if (command_line_.HasSwitch(switches::kRemoteDebuggingPort)) { 668 std::string port_str = 669 command_line_.GetSwitchValueASCII(switches::kRemoteDebuggingPort); 670 int64 port; 671 if (base::StringToInt64(port_str, &port) && port > 0 && port < 65535) { 672 g_browser_process->InitDevToolsHttpProtocolHandler( 673 "127.0.0.1", 674 static_cast<int>(port), 675 ""); 676 } else { 677 DLOG(WARNING) << "Invalid http debugger port number " << port; 678 } 679 } 680 681 if (command_line_.HasSwitch(switches::kUserAgent)) { 682 webkit_glue::SetUserAgent(command_line_.GetSwitchValueASCII( 683 switches::kUserAgent)); 684 } 685 686 // Open the required browser windows and tabs. First, see if 687 // we're being run as an application window. If so, the user 688 // opened an app shortcut. Don't restore tabs or open initial 689 // URLs in that case. The user should see the window as an app, 690 // not as chrome. 691 if (OpenApplicationWindow(profile)) { 692 RecordLaunchModeHistogram(LM_AS_WEBAPP); 693 } else { 694 RecordLaunchModeHistogram(urls_to_open.empty()? 695 LM_TO_BE_DECIDED : LM_WITH_URLS); 696 ProcessLaunchURLs(process_startup, urls_to_open); 697 698 // If this is an app launch, but we didn't open an app window, it may 699 // be an app tab. 700 OpenApplicationTab(profile); 701 702 if (process_startup) { 703 if (browser_defaults::kOSSupportsOtherBrowsers && 704 !command_line_.HasSwitch(switches::kNoDefaultBrowserCheck)) { 705 // Check whether we are the default browser. 706 CheckDefaultBrowser(profile); 707 } 708 #if defined(OS_MACOSX) 709 // Check whether the auto-update system needs to be promoted from user 710 // to system. 711 KeystoneInfoBar::PromotionInfoBar(profile); 712 #endif 713 } 714 } 715 716 #if defined(OS_WIN) 717 // Print the selected page if the command line switch exists. Note that the 718 // current selected tab would be the page which will be printed. 719 if (command_line_.HasSwitch(switches::kPrint)) { 720 Browser* browser = BrowserList::GetLastActive(); 721 browser->Print(); 722 } 723 #endif 724 725 // If we're recording or playing back, startup the EventRecorder now 726 // unless otherwise specified. 727 if (!command_line_.HasSwitch(switches::kNoEvents)) { 728 FilePath script_path; 729 PathService::Get(chrome::FILE_RECORDED_SCRIPT, &script_path); 730 731 bool record_mode = command_line_.HasSwitch(switches::kRecordMode); 732 bool playback_mode = command_line_.HasSwitch(switches::kPlaybackMode); 733 734 if (record_mode && chrome::kRecordModeEnabled) 735 base::EventRecorder::current()->StartRecording(script_path); 736 if (playback_mode) 737 base::EventRecorder::current()->StartPlayback(script_path); 738 } 739 740 #if defined(OS_WIN) 741 if (process_startup) 742 ShellIntegration::MigrateChromiumShortcuts(); 743 #endif // defined(OS_WIN) 744 745 return true; 746 } 747 748 bool BrowserInit::LaunchWithProfile::IsAppLaunch(std::string* app_url, 749 std::string* app_id) { 750 if (command_line_.HasSwitch(switches::kApp)) { 751 if (app_url) 752 *app_url = command_line_.GetSwitchValueASCII(switches::kApp); 753 return true; 754 } 755 if (command_line_.HasSwitch(switches::kAppId)) { 756 if (app_id) 757 *app_id = command_line_.GetSwitchValueASCII(switches::kAppId); 758 return true; 759 } 760 return false; 761 } 762 763 bool BrowserInit::LaunchWithProfile::OpenApplicationTab(Profile* profile) { 764 std::string app_id; 765 // App shortcuts to URLs always open in an app window. Because this 766 // function will open an app that should be in a tab, there is no need 767 // to look at the app URL. OpenApplicationWindow() will open app url 768 // shortcuts. 769 if (!IsAppLaunch(NULL, &app_id) || app_id.empty()) 770 return false; 771 772 extension_misc::LaunchContainer launch_container; 773 const Extension* extension; 774 if (!GetAppLaunchContainer(profile, app_id, &extension, &launch_container)) 775 return false; 776 777 // If the user doesn't want to open a tab, fail. 778 if (launch_container != extension_misc::LAUNCH_TAB) 779 return false; 780 781 RecordCmdLineAppHistogram(); 782 783 TabContents* app_tab = Browser::OpenApplicationTab(profile, extension, NULL); 784 return (app_tab != NULL); 785 } 786 787 bool BrowserInit::LaunchWithProfile::OpenApplicationWindow(Profile* profile) { 788 std::string url_string, app_id; 789 if (!IsAppLaunch(&url_string, &app_id)) 790 return false; 791 792 // This can fail if the app_id is invalid. It can also fail if the 793 // extension is external, and has not yet been installed. 794 // TODO(skerner): Do something reasonable here. Pop up a warning panel? 795 // Open an URL to the gallery page of the extension id? 796 if (!app_id.empty()) { 797 extension_misc::LaunchContainer launch_container; 798 const Extension* extension; 799 if (!GetAppLaunchContainer(profile, app_id, &extension, &launch_container)) 800 return false; 801 802 // TODO(skerner): Could pass in |extension| and |launch_container|, 803 // and avoid calling GetAppLaunchContainer() both here and in 804 // OpenApplicationTab(). 805 806 if (launch_container == extension_misc::LAUNCH_TAB) 807 return false; 808 809 RecordCmdLineAppHistogram(); 810 TabContents* tab_in_app_window = Browser::OpenApplication( 811 profile, extension, launch_container, NULL); 812 return (tab_in_app_window != NULL); 813 } 814 815 if (url_string.empty()) 816 return false; 817 818 #if defined(OS_WIN) // Fix up Windows shortcuts. 819 ReplaceSubstringsAfterOffset(&url_string, 0, "\\x", "%"); 820 #endif 821 GURL url(url_string); 822 823 // Restrict allowed URLs for --app switch. 824 if (!url.is_empty() && url.is_valid()) { 825 ChildProcessSecurityPolicy *policy = 826 ChildProcessSecurityPolicy::GetInstance(); 827 if (policy->IsWebSafeScheme(url.scheme()) || 828 url.SchemeIs(chrome::kFileScheme)) { 829 830 if (profile->GetExtensionService()->IsInstalledApp(url)) { 831 RecordCmdLineAppHistogram(); 832 } else { 833 UMA_HISTOGRAM_ENUMERATION( 834 extension_misc::kAppLaunchHistogram, 835 extension_misc::APP_LAUNCH_CMD_LINE_APP_LEGACY, 836 extension_misc::APP_LAUNCH_BUCKET_BOUNDARY); 837 } 838 TabContents* app_tab = Browser::OpenAppShortcutWindow( 839 profile, 840 url, 841 true); // Update app info. 842 return (app_tab != NULL); 843 } 844 } 845 return false; 846 } 847 848 void BrowserInit::LaunchWithProfile::ProcessLaunchURLs( 849 bool process_startup, 850 const std::vector<GURL>& urls_to_open) { 851 // If we're starting up in "background mode" (no open browser window) then 852 // don't open any browser windows. 853 if (process_startup && command_line_.HasSwitch(switches::kNoStartupWindow)) 854 return; 855 856 if (process_startup && ProcessStartupURLs(urls_to_open)) { 857 // ProcessStartupURLs processed the urls, nothing else to do. 858 return; 859 } 860 861 if (!process_startup && 862 (profile_->GetSessionService() && 863 profile_->GetSessionService()->RestoreIfNecessary(urls_to_open))) { 864 // We're already running and session restore wanted to run. This can happen 865 // at various points, such as if there is only an app window running and the 866 // user double clicked the chrome icon. Return so we don't open the urls. 867 return; 868 } 869 870 // Session restore didn't occur, open the urls. 871 872 Browser* browser = NULL; 873 std::vector<GURL> adjust_urls = urls_to_open; 874 if (adjust_urls.empty()) 875 AddStartupURLs(&adjust_urls); 876 else if (!command_line_.HasSwitch(switches::kOpenInNewWindow)) 877 browser = BrowserList::GetLastActiveWithProfile(profile_); 878 879 browser = OpenURLsInBrowser(browser, process_startup, adjust_urls); 880 if (process_startup) 881 AddInfoBarsIfNecessary(browser); 882 } 883 884 bool BrowserInit::LaunchWithProfile::ProcessStartupURLs( 885 const std::vector<GURL>& urls_to_open) { 886 SessionStartupPref pref = GetSessionStartupPref(command_line_, profile_); 887 if (command_line_.HasSwitch(switches::kTestingChannelID) && 888 !command_line_.HasSwitch(switches::kRestoreLastSession) && 889 browser_defaults::kDefaultSessionStartupType != 890 SessionStartupPref::DEFAULT) { 891 // When we have non DEFAULT session start type, then we won't open up a 892 // fresh session. But none of the tests are written with this in mind, so 893 // we explicitly ignore it during testing. 894 return false; 895 } 896 897 if (pref.type == SessionStartupPref::LAST) { 898 if (!profile_->DidLastSessionExitCleanly() && 899 !command_line_.HasSwitch(switches::kRestoreLastSession)) { 900 // The last session crashed. It's possible automatically loading the 901 // page will trigger another crash, locking the user out of chrome. 902 // To avoid this, don't restore on startup but instead show the crashed 903 // infobar. 904 return false; 905 } 906 Browser* browser = 907 SessionRestore::RestoreSessionSynchronously(profile_, urls_to_open); 908 AddInfoBarsIfNecessary(browser); 909 return true; 910 } 911 912 std::vector<Tab> tabs = PinnedTabCodec::ReadPinnedTabs(profile_); 913 914 RecordAppLaunches(profile_, urls_to_open, tabs); 915 916 if (!urls_to_open.empty()) { 917 // If urls were specified on the command line, use them. 918 UrlsToTabs(urls_to_open, &tabs); 919 } else if (pref.type == SessionStartupPref::URLS && !pref.urls.empty()) { 920 // Only use the set of urls specified in preferences if nothing was 921 // specified on the command line. Filter out any urls that are to be 922 // restored by virtue of having been previously pinned. 923 AddUniqueURLs(pref.urls, &tabs); 924 } else if (pref.type == SessionStartupPref::DEFAULT && !tabs.empty()) { 925 // Make sure the home page is opened even if there are pinned tabs. 926 std::vector<GURL> urls; 927 AddStartupURLs(&urls); 928 UrlsToTabs(urls, &tabs); 929 } 930 931 if (tabs.empty()) 932 return false; 933 934 Browser* browser = OpenTabsInBrowser(NULL, true, tabs); 935 AddInfoBarsIfNecessary(browser); 936 return true; 937 } 938 939 void BrowserInit::LaunchWithProfile::AddUniqueURLs( 940 const std::vector<GURL>& urls, 941 std::vector<Tab>* tabs) { 942 size_t num_existing_tabs = tabs->size(); 943 for (size_t i = 0; i < urls.size(); ++i) { 944 bool in_tabs = false; 945 for (size_t j = 0; j < num_existing_tabs; ++j) { 946 if (urls[i] == (*tabs)[j].url) { 947 in_tabs = true; 948 break; 949 } 950 } 951 if (!in_tabs) { 952 BrowserInit::LaunchWithProfile::Tab tab; 953 tab.is_pinned = false; 954 tab.url = urls[i]; 955 tabs->push_back(tab); 956 } 957 } 958 } 959 960 Browser* BrowserInit::LaunchWithProfile::OpenURLsInBrowser( 961 Browser* browser, 962 bool process_startup, 963 const std::vector<GURL>& urls) { 964 std::vector<Tab> tabs; 965 UrlsToTabs(urls, &tabs); 966 return OpenTabsInBrowser(browser, process_startup, tabs); 967 } 968 969 Browser* BrowserInit::LaunchWithProfile::OpenTabsInBrowser( 970 Browser* browser, 971 bool process_startup, 972 const std::vector<Tab>& tabs) { 973 DCHECK(!tabs.empty()); 974 // If we don't yet have a profile, try to use the one we're given from 975 // |browser|. While we may not end up actually using |browser| (since it 976 // could be a popup window), we can at least use the profile. 977 if (!profile_ && browser) 978 profile_ = browser->profile(); 979 980 if (!browser || browser->type() != Browser::TYPE_NORMAL) { 981 browser = Browser::Create(profile_); 982 } else { 983 #if defined(TOOLKIT_GTK) 984 // Setting the time of the last action on the window here allows us to steal 985 // focus, which is what the user wants when opening a new tab in an existing 986 // browser window. 987 gtk_util::SetWMLastUserActionTime(browser->window()->GetNativeHandle()); 988 #endif 989 } 990 991 #if !defined(OS_MACOSX) 992 // In kiosk mode, we want to always be fullscreen, so switch to that now. 993 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kKioskMode)) 994 browser->ToggleFullscreenMode(); 995 #endif 996 997 bool first_tab = true; 998 for (size_t i = 0; i < tabs.size(); ++i) { 999 // We skip URLs that we'd have to launch an external protocol handler for. 1000 // This avoids us getting into an infinite loop asking ourselves to open 1001 // a URL, should the handler be (incorrectly) configured to be us. Anyone 1002 // asking us to open such a URL should really ask the handler directly. 1003 if (!process_startup && !net::URLRequest::IsHandledURL(tabs[i].url)) 1004 continue; 1005 1006 int add_types = first_tab ? TabStripModel::ADD_ACTIVE : 1007 TabStripModel::ADD_NONE; 1008 add_types |= TabStripModel::ADD_FORCE_INDEX; 1009 if (tabs[i].is_pinned) 1010 add_types |= TabStripModel::ADD_PINNED; 1011 int index = browser->GetIndexForInsertionDuringRestore(i); 1012 1013 browser::NavigateParams params(browser, tabs[i].url, 1014 PageTransition::START_PAGE); 1015 params.disposition = first_tab ? NEW_FOREGROUND_TAB : NEW_BACKGROUND_TAB; 1016 params.tabstrip_index = index; 1017 params.tabstrip_add_types = add_types; 1018 params.extension_app_id = tabs[i].app_id; 1019 browser::Navigate(¶ms); 1020 1021 first_tab = false; 1022 } 1023 browser->window()->Show(); 1024 // TODO(jcampan): http://crbug.com/8123 we should not need to set the initial 1025 // focus explicitly. 1026 browser->GetSelectedTabContents()->view()->SetInitialFocus(); 1027 1028 return browser; 1029 } 1030 1031 void BrowserInit::LaunchWithProfile::AddInfoBarsIfNecessary(Browser* browser) { 1032 if (!browser || !profile_ || browser->tab_count() == 0) 1033 return; 1034 1035 TabContents* tab_contents = browser->GetSelectedTabContents(); 1036 AddCrashedInfoBarIfNecessary(tab_contents); 1037 AddBadFlagsInfoBarIfNecessary(tab_contents); 1038 AddDNSCertProvenanceCheckingWarningInfoBarIfNecessary(tab_contents); 1039 AddObsoleteSystemInfoBarIfNecessary(tab_contents); 1040 } 1041 1042 void BrowserInit::LaunchWithProfile::AddCrashedInfoBarIfNecessary( 1043 TabContents* tab) { 1044 // Assume that if the user is launching incognito they were previously 1045 // running incognito so that we have nothing to restore from. 1046 if (!profile_->DidLastSessionExitCleanly() && 1047 !profile_->IsOffTheRecord()) { 1048 // The last session didn't exit cleanly. Show an infobar to the user 1049 // so that they can restore if they want. The delegate deletes itself when 1050 // it is closed. 1051 tab->AddInfoBar(new SessionCrashedInfoBarDelegate(tab)); 1052 } 1053 } 1054 1055 void BrowserInit::LaunchWithProfile::AddBadFlagsInfoBarIfNecessary( 1056 TabContents* tab) { 1057 // Unsupported flags for which to display a warning that "stability and 1058 // security will suffer". 1059 static const char* kBadFlags[] = { 1060 // These imply disabling the sandbox. 1061 switches::kSingleProcess, 1062 switches::kNoSandbox, 1063 switches::kInProcessWebGL, 1064 // These are scary features for developers that shouldn't be turned on 1065 // persistently. 1066 switches::kEnableNaCl, 1067 NULL 1068 }; 1069 1070 const char* bad_flag = NULL; 1071 for (const char** flag = kBadFlags; *flag; ++flag) { 1072 if (command_line_.HasSwitch(*flag)) { 1073 bad_flag = *flag; 1074 break; 1075 } 1076 } 1077 1078 if (bad_flag) { 1079 tab->AddInfoBar(new SimpleAlertInfoBarDelegate(tab, NULL, 1080 l10n_util::GetStringFUTF16(IDS_BAD_FLAGS_WARNING_MESSAGE, 1081 UTF8ToUTF16(std::string("--") + bad_flag)), 1082 false)); 1083 } 1084 } 1085 1086 class LearnMoreInfoBar : public LinkInfoBarDelegate { 1087 public: 1088 explicit LearnMoreInfoBar(TabContents* tab_contents, 1089 const string16& message, 1090 const GURL& url); 1091 virtual ~LearnMoreInfoBar(); 1092 1093 virtual string16 GetMessageTextWithOffset(size_t* link_offset) const OVERRIDE; 1094 virtual string16 GetLinkText() const OVERRIDE; 1095 virtual bool LinkClicked(WindowOpenDisposition disposition) OVERRIDE; 1096 1097 private: 1098 TabContents* const tab_contents_; 1099 string16 message_; 1100 GURL learn_more_url_; 1101 1102 DISALLOW_COPY_AND_ASSIGN(LearnMoreInfoBar); 1103 }; 1104 1105 LearnMoreInfoBar::LearnMoreInfoBar(TabContents* tab_contents, 1106 const string16& message, 1107 const GURL& url) 1108 : LinkInfoBarDelegate(tab_contents), 1109 tab_contents_(tab_contents), 1110 message_(message), 1111 learn_more_url_(url) { 1112 } 1113 1114 LearnMoreInfoBar::~LearnMoreInfoBar() { 1115 } 1116 1117 string16 LearnMoreInfoBar::GetMessageTextWithOffset(size_t* link_offset) const { 1118 string16 text = message_; 1119 text.push_back(' '); // Add a space before the following link. 1120 *link_offset = text.size(); 1121 return text; 1122 } 1123 1124 string16 LearnMoreInfoBar::GetLinkText() const { 1125 return l10n_util::GetStringUTF16(IDS_LEARN_MORE); 1126 } 1127 1128 bool LearnMoreInfoBar::LinkClicked(WindowOpenDisposition disposition) { 1129 tab_contents_->OpenURL(learn_more_url_, GURL(), disposition, 1130 PageTransition::LINK); 1131 return false; 1132 } 1133 1134 // This is the page which provides information on DNS certificate provenance 1135 // checking. 1136 void BrowserInit::LaunchWithProfile:: 1137 AddDNSCertProvenanceCheckingWarningInfoBarIfNecessary(TabContents* tab) { 1138 if (!command_line_.HasSwitch(switches::kEnableDNSCertProvenanceChecking)) 1139 return; 1140 1141 const char* kLearnMoreURL = 1142 "http://dev.chromium.org/dnscertprovenancechecking"; 1143 string16 message = l10n_util::GetStringUTF16( 1144 IDS_DNS_CERT_PROVENANCE_CHECKING_WARNING_MESSAGE); 1145 tab->AddInfoBar(new LearnMoreInfoBar(tab, 1146 message, 1147 GURL(kLearnMoreURL))); 1148 } 1149 1150 void BrowserInit::LaunchWithProfile::AddObsoleteSystemInfoBarIfNecessary( 1151 TabContents* tab) { 1152 #if defined(TOOLKIT_USES_GTK) 1153 // We've deprecated support for Ubuntu Hardy. Rather than attempting to 1154 // determine whether you're using that, we instead key off the GTK version; 1155 // this will also deprecate other distributions (including variants of Ubuntu) 1156 // that are of a similar age. 1157 // Version key: 1158 // Ubuntu Hardy: GTK 2.12 1159 // RHEL 6: GTK 2.18 1160 // Ubuntu Lucid: GTK 2.20 1161 if (gtk_check_version(2, 18, 0)) { 1162 string16 message = 1163 l10n_util::GetStringFUTF16(IDS_SYSTEM_OBSOLETE_MESSAGE, 1164 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)); 1165 // Link to an article in the help center on minimum system requirements. 1166 const char* kLearnMoreURL = 1167 "http://www.google.com/support/chrome/bin/answer.py?answer=95411"; 1168 tab->AddInfoBar(new LearnMoreInfoBar(tab, 1169 message, 1170 GURL(kLearnMoreURL))); 1171 } 1172 #endif 1173 } 1174 1175 void BrowserInit::LaunchWithProfile::AddStartupURLs( 1176 std::vector<GURL>* startup_urls) const { 1177 // If we have urls specified beforehand (i.e. from command line) use them 1178 // and nothing else. 1179 if (!startup_urls->empty()) 1180 return; 1181 // If we have urls specified by the first run master preferences use them 1182 // and nothing else. 1183 if (browser_init_) { 1184 if (!browser_init_->first_run_tabs_.empty()) { 1185 std::vector<GURL>::iterator it = browser_init_->first_run_tabs_.begin(); 1186 while (it != browser_init_->first_run_tabs_.end()) { 1187 // Replace magic names for the actual urls. 1188 if (it->host() == "new_tab_page") { 1189 startup_urls->push_back(GURL(chrome::kChromeUINewTabURL)); 1190 } else if (it->host() == "welcome_page") { 1191 startup_urls->push_back(GetWelcomePageURL()); 1192 } else { 1193 startup_urls->push_back(*it); 1194 } 1195 ++it; 1196 } 1197 browser_init_->first_run_tabs_.clear(); 1198 return; 1199 } 1200 } 1201 1202 // Otherwise open at least the new tab page (and the welcome page, if this 1203 // is the first time the browser is being started), or the set of URLs 1204 // specified on the command line. 1205 startup_urls->push_back(GURL()); // New tab page. 1206 PrefService* prefs = g_browser_process->local_state(); 1207 if (prefs->FindPreference(prefs::kShouldShowWelcomePage) && 1208 prefs->GetBoolean(prefs::kShouldShowWelcomePage)) { 1209 // Reset the preference so we don't show the welcome page next time. 1210 prefs->ClearPref(prefs::kShouldShowWelcomePage); 1211 startup_urls->push_back(GetWelcomePageURL()); 1212 } 1213 } 1214 1215 void BrowserInit::LaunchWithProfile::CheckDefaultBrowser(Profile* profile) { 1216 // We do not check if we are the default browser if: 1217 // - the user said "don't ask me again" on the infobar earlier. 1218 // - this is the first launch after the first run flow. 1219 // - There is a policy in control of this setting. 1220 if (!profile->GetPrefs()->GetBoolean(prefs::kCheckDefaultBrowser) || 1221 FirstRun::IsChromeFirstRun()) { 1222 return; 1223 } 1224 if (g_browser_process->local_state()->IsManagedPreference( 1225 prefs::kDefaultBrowserSettingEnabled)) { 1226 if (g_browser_process->local_state()->GetBoolean( 1227 prefs::kDefaultBrowserSettingEnabled)) { 1228 BrowserThread::PostTask( 1229 BrowserThread::FILE, FROM_HERE, NewRunnableFunction( 1230 &ShellIntegration::SetAsDefaultBrowser)); 1231 } else { 1232 // TODO(pastarmovj): We can't really do anything meaningful here yet but 1233 // just prevent showing the infobar. 1234 } 1235 return; 1236 } 1237 BrowserThread::PostTask( 1238 BrowserThread::FILE, FROM_HERE, new CheckDefaultBrowserTask()); 1239 } 1240 1241 std::vector<GURL> BrowserInit::GetURLsFromCommandLine( 1242 const CommandLine& command_line, 1243 const FilePath& cur_dir, 1244 Profile* profile) { 1245 std::vector<GURL> urls; 1246 const std::vector<CommandLine::StringType>& params = command_line.args(); 1247 1248 for (size_t i = 0; i < params.size(); ++i) { 1249 FilePath param = FilePath(params[i]); 1250 // Handle Vista way of searching - "? <search-term>" 1251 if (param.value().size() > 2 && 1252 param.value()[0] == '?' && param.value()[1] == ' ') { 1253 const TemplateURL* default_provider = 1254 profile->GetTemplateURLModel()->GetDefaultSearchProvider(); 1255 if (default_provider && default_provider->url()) { 1256 const TemplateURLRef* search_url = default_provider->url(); 1257 DCHECK(search_url->SupportsReplacement()); 1258 string16 search_term = param.LossyDisplayName().substr(2); 1259 urls.push_back(GURL(search_url->ReplaceSearchTerms( 1260 *default_provider, search_term, 1261 TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, 1262 string16()))); 1263 continue; 1264 } 1265 } 1266 1267 // Otherwise, fall through to treating it as a URL. 1268 1269 // This will create a file URL or a regular URL. 1270 // This call can (in rare circumstances) block the UI thread. 1271 // Allow it until this bug is fixed. 1272 // http://code.google.com/p/chromium/issues/detail?id=60641 1273 GURL url; 1274 { 1275 base::ThreadRestrictions::ScopedAllowIO allow_io; 1276 url = URLFixerUpper::FixupRelativeFile(cur_dir, param); 1277 } 1278 // Exclude dangerous schemes. 1279 if (url.is_valid()) { 1280 ChildProcessSecurityPolicy *policy = 1281 ChildProcessSecurityPolicy::GetInstance(); 1282 if (policy->IsWebSafeScheme(url.scheme()) || 1283 url.SchemeIs(chrome::kFileScheme) || 1284 #if defined(OS_CHROMEOS) 1285 // In ChromeOS, allow a settings page to be specified on the 1286 // command line. See ExistingUserController::OnLoginSuccess. 1287 (url.spec().find(chrome::kChromeUISettingsURL) == 0) || 1288 #endif 1289 (url.spec().compare(chrome::kAboutBlankURL) == 0)) { 1290 urls.push_back(url); 1291 } 1292 } 1293 } 1294 return urls; 1295 } 1296 1297 bool BrowserInit::ProcessCmdLineImpl(const CommandLine& command_line, 1298 const FilePath& cur_dir, 1299 bool process_startup, 1300 Profile* profile, 1301 int* return_code, 1302 BrowserInit* browser_init) { 1303 DCHECK(profile); 1304 if (process_startup) { 1305 if (command_line.HasSwitch(switches::kDisablePromptOnRepost)) 1306 NavigationController::DisablePromptOnRepost(); 1307 1308 // Look for the testing channel ID ONLY during process startup 1309 if (command_line.HasSwitch(switches::kTestingChannelID)) { 1310 std::string testing_channel_id = command_line.GetSwitchValueASCII( 1311 switches::kTestingChannelID); 1312 // TODO(sanjeevr) Check if we need to make this a singleton for 1313 // compatibility with the old testing code 1314 // If there are any extra parameters, we expect each one to generate a 1315 // new tab; if there are none then we get one homepage tab. 1316 int expected_tab_count = 1; 1317 if (command_line.HasSwitch(switches::kNoStartupWindow)) { 1318 expected_tab_count = 0; 1319 #if defined(OS_CHROMEOS) 1320 // kLoginManager will cause Chrome to start up with the ChromeOS login 1321 // screen instead of a browser window, so it won't load any tabs. 1322 } else if (command_line.HasSwitch(switches::kLoginManager)) { 1323 expected_tab_count = 0; 1324 #endif 1325 } else if (command_line.HasSwitch(switches::kRestoreLastSession)) { 1326 std::string restore_session_value( 1327 command_line.GetSwitchValueASCII(switches::kRestoreLastSession)); 1328 base::StringToInt(restore_session_value, &expected_tab_count); 1329 } else { 1330 std::vector<GURL> urls_to_open = GetURLsFromCommandLine( 1331 command_line, cur_dir, profile); 1332 expected_tab_count = 1333 std::max(1, static_cast<int>(urls_to_open.size())); 1334 } 1335 if (!CreateAutomationProvider<TestingAutomationProvider>( 1336 testing_channel_id, 1337 profile, 1338 static_cast<size_t>(expected_tab_count))) 1339 return false; 1340 } 1341 } 1342 1343 bool silent_launch = false; 1344 1345 if (command_line.HasSwitch(switches::kAutomationClientChannelID)) { 1346 std::string automation_channel_id = command_line.GetSwitchValueASCII( 1347 switches::kAutomationClientChannelID); 1348 // If there are any extra parameters, we expect each one to generate a 1349 // new tab; if there are none then we have no tabs 1350 std::vector<GURL> urls_to_open = GetURLsFromCommandLine( 1351 command_line, cur_dir, profile); 1352 size_t expected_tabs = 1353 std::max(static_cast<int>(urls_to_open.size()), 0); 1354 if (expected_tabs == 0) 1355 silent_launch = true; 1356 1357 if (command_line.HasSwitch(switches::kChromeFrame)) { 1358 if (!CreateAutomationProvider<ChromeFrameAutomationProvider>( 1359 automation_channel_id, profile, expected_tabs)) 1360 return false; 1361 } else { 1362 if (!CreateAutomationProvider<AutomationProvider>( 1363 automation_channel_id, profile, expected_tabs)) 1364 return false; 1365 } 1366 } 1367 1368 // If we have been invoked to display a desktop notification on behalf of 1369 // the service process, we do not want to open any browser windows. 1370 if (command_line.HasSwitch(switches::kNotifyCloudPrintTokenExpired)) { 1371 silent_launch = true; 1372 profile->GetCloudPrintProxyService()->ShowTokenExpiredNotification(); 1373 } 1374 1375 // If we are just displaying a print dialog we shouldn't open browser 1376 // windows. 1377 if (print_dialog_cloud::CreatePrintDialogFromCommandLine(command_line)) { 1378 silent_launch = true; 1379 } 1380 1381 if (command_line.HasSwitch(switches::kExplicitlyAllowedPorts)) { 1382 std::string allowed_ports = 1383 command_line.GetSwitchValueASCII(switches::kExplicitlyAllowedPorts); 1384 net::SetExplicitlyAllowedPorts(allowed_ports); 1385 } 1386 1387 #if defined(OS_CHROMEOS) 1388 // The browser will be launched after the user logs in. 1389 if (command_line.HasSwitch(switches::kLoginManager) || 1390 command_line.HasSwitch(switches::kLoginPassword)) { 1391 silent_launch = true; 1392 } 1393 #endif 1394 1395 #if defined(HAVE_XINPUT2) && defined(TOUCH_UI) 1396 // Get a list of pointer-devices that should be treated as touch-devices. 1397 // TODO(sad): Instead of/in addition to getting the list from the 1398 // command-line, query X for a list of touch devices. 1399 std::string touch_devices = 1400 command_line.GetSwitchValueASCII(switches::kTouchDevices); 1401 1402 if (!touch_devices.empty()) { 1403 std::vector<std::string> devs; 1404 std::vector<unsigned int> device_ids; 1405 unsigned int devid; 1406 base::SplitString(touch_devices, ',', &devs); 1407 for (std::vector<std::string>::iterator iter = devs.begin(); 1408 iter != devs.end(); ++iter) { 1409 if (base::StringToInt(*iter, reinterpret_cast<int*>(&devid))) { 1410 device_ids.push_back(devid); 1411 } else { 1412 DLOG(WARNING) << "Invalid touch-device id: " << *iter; 1413 } 1414 } 1415 views::SetTouchDeviceList(device_ids); 1416 } 1417 #endif 1418 1419 // If we don't want to launch a new browser window or tab (in the case 1420 // of an automation request), we are done here. 1421 if (!silent_launch) { 1422 return browser_init->LaunchBrowser( 1423 command_line, profile, cur_dir, process_startup, return_code); 1424 } 1425 return true; 1426 } 1427 1428 template <class AutomationProviderClass> 1429 bool BrowserInit::CreateAutomationProvider(const std::string& channel_id, 1430 Profile* profile, 1431 size_t expected_tabs) { 1432 scoped_refptr<AutomationProviderClass> automation = 1433 new AutomationProviderClass(profile); 1434 1435 if (!automation->InitializeChannel(channel_id)) 1436 return false; 1437 automation->SetExpectedTabCount(expected_tabs); 1438 1439 AutomationProviderList* list = 1440 g_browser_process->InitAutomationProviderList(); 1441 DCHECK(list); 1442 list->AddProvider(automation); 1443 1444 return true; 1445 } 1446