browser_main.cc revision c407dc5cd9bdc5668497f21b26b09d988ab439de
1// Copyright (c) 2010 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/browser_main.h" 6 7#include <algorithm> 8#include <string> 9#include <vector> 10 11#include "app/hi_res_timer_manager.h" 12#include "app/l10n_util.h" 13#include "app/resource_bundle.h" 14#include "app/system_monitor.h" 15#include "base/command_line.h" 16#include "base/field_trial.h" 17#include "base/file_util.h" 18#include "base/histogram.h" 19#include "base/scoped_nsautorelease_pool.h" 20#include "base/path_service.h" 21#include "base/platform_thread.h" 22#include "base/process_util.h" 23#include "base/string_piece.h" 24#include "base/string_util.h" 25#include "base/sys_string_conversions.h" 26#include "base/time.h" 27#include "base/values.h" 28#include "build/build_config.h" 29#include "chrome/browser/browser.h" 30#include "chrome/browser/browser_main_win.h" 31#include "chrome/browser/browser_init.h" 32#include "chrome/browser/browser_prefs.h" 33#include "chrome/browser/browser_process.h" 34#include "chrome/browser/browser_process_impl.h" 35#include "chrome/browser/browser_shutdown.h" 36#include "chrome/browser/chrome_thread.h" 37#include "chrome/browser/dom_ui/chrome_url_data_manager.h" 38#include "chrome/browser/extensions/extension_protocols.h" 39#include "chrome/browser/extensions/extensions_service.h" 40#include "chrome/browser/first_run.h" 41#include "chrome/browser/jankometer.h" 42#include "chrome/browser/metrics/histogram_synchronizer.h" 43#include "chrome/browser/metrics/metrics_log.h" 44#include "chrome/browser/metrics/metrics_service.h" 45#include "chrome/browser/net/predictor_api.h" 46#include "chrome/browser/net/metadata_url_request.h" 47#include "chrome/browser/net/sdch_dictionary_fetcher.h" 48#include "chrome/browser/net/websocket_experiment/websocket_experiment_runner.h" 49#include "chrome/browser/plugin_service.h" 50#include "chrome/browser/pref_service.h" 51#include "chrome/browser/pref_value_store.h" 52#include "chrome/browser/process_singleton.h" 53#include "chrome/browser/profile.h" 54#include "chrome/browser/profile_manager.h" 55#include "chrome/browser/renderer_host/resource_dispatcher_host.h" 56#include "chrome/browser/search_engines/template_url_model.h" 57#include "chrome/browser/search_engines/template_url_prepopulate_data.h" 58#include "chrome/browser/shell_integration.h" 59#include "chrome/browser/translate/translate_manager.h" 60#include "chrome/common/child_process.h" 61#include "chrome/common/chrome_constants.h" 62#include "chrome/common/chrome_paths.h" 63#include "chrome/common/chrome_switches.h" 64#include "chrome/common/json_pref_store.h" 65#include "chrome/common/jstemplate_builder.h" 66#include "chrome/common/main_function_params.h" 67#include "chrome/common/net/net_resource_provider.h" 68#include "chrome/common/pref_names.h" 69#include "chrome/common/result_codes.h" 70#include "chrome/installer/util/google_update_settings.h" 71#include "chrome/installer/util/master_preferences.h" 72#include "grit/app_locale_settings.h" 73#include "grit/chromium_strings.h" 74#include "grit/generated_resources.h" 75#include "net/base/cookie_monster.h" 76#include "net/base/net_module.h" 77#include "net/base/network_change_notifier.h" 78#include "net/http/http_network_layer.h" 79#include "net/http/http_network_session.h" 80#include "net/http/http_network_transaction.h" 81#include "net/socket/client_socket_pool_base.h" 82#include "net/spdy/spdy_session_pool.h" 83 84#if defined(USE_LINUX_BREAKPAD) 85#include "base/linux_util.h" 86#include "chrome/app/breakpad_linux.h" 87#endif 88 89#if defined(OS_POSIX) && !defined(OS_MACOSX) 90#include "chrome/browser/gtk/gtk_util.h" 91#endif 92 93#if defined(OS_CHROMEOS) 94#include "chrome/browser/chromeos/boot_times_loader.h" 95#endif 96 97// TODO(port): several win-only methods have been pulled out of this, but 98// BrowserMain() as a whole needs to be broken apart so that it's usable by 99// other platforms. For now, it's just a stub. This is a serious work in 100// progress and should not be taken as an indication of a real refactoring. 101 102#if defined(OS_WIN) 103#include <windows.h> 104#include <commctrl.h> 105#include <shellapi.h> 106 107#include "app/l10n_util_win.h" 108#include "app/win_util.h" 109#include "base/registry.h" 110#include "base/win_util.h" 111#include "chrome/browser/browser.h" 112#include "chrome/browser/browser_trial.h" 113#include "chrome/browser/metrics/user_metrics.h" 114#include "chrome/browser/net/url_fixer_upper.h" 115#include "chrome/browser/rlz/rlz.h" 116#include "chrome/browser/views/user_data_dir_dialog.h" 117#include "chrome/common/env_vars.h" 118#include "chrome/common/sandbox_policy.h" 119#include "chrome/installer/util/helper.h" 120#include "chrome/installer/util/install_util.h" 121#include "chrome/installer/util/shell_util.h" 122#include "chrome/installer/util/version.h" 123#include "net/base/net_util.h" 124#include "net/base/sdch_manager.h" 125#include "net/socket/ssl_client_socket_nss_factory.h" 126#include "printing/printed_document.h" 127#include "sandbox/src/sandbox.h" 128#endif // defined(OS_WIN) 129 130#if defined(OS_MACOSX) 131#include <Security/Security.h> 132#include "chrome/browser/cocoa/install_from_dmg.h" 133#include "net/socket/ssl_client_socket_mac_factory.h" 134#endif 135 136#if defined(OS_MACOSX) || defined(OS_WIN) 137#include "base/nss_util.h" 138#endif 139 140#if defined(TOOLKIT_VIEWS) 141#include "chrome/browser/views/chrome_views_delegate.h" 142#include "views/focus/accelerator_handler.h" 143#endif 144 145#if defined(OS_CHROMEOS) 146#include "chrome/browser/chromeos/cros/cros_library.h" 147#include "chrome/browser/chromeos/cros/screen_lock_library.h" 148#include "chrome/browser/chromeos/customization_document.h" 149#include "chrome/browser/chromeos/external_metrics.h" 150#include "chrome/browser/chromeos/login/screen_locker.h" 151#include "chrome/browser/chromeos/login/user_manager.h" 152#include "chrome/browser/views/browser_dialogs.h" 153#endif 154 155// BrowserMainParts ------------------------------------------------------------ 156 157BrowserMainParts::BrowserMainParts(const MainFunctionParams& parameters) 158 : parameters_(parameters), 159 parsed_command_line_(parameters.command_line_) { 160} 161 162// BrowserMainParts: EarlyInitialization() and related ------------------------- 163 164void BrowserMainParts::EarlyInitialization() { 165 PreEarlyInitialization(); 166 167 ConnectionFieldTrial(); 168 SocketTimeoutFieldTrial(); 169 SpdyFieldTrial(); 170 InitializeSSL(); // TODO(viettrungluu): move to platform-specific method(s) 171 172 PostEarlyInitialization(); 173} 174 175// This is an A/B test for the maximum number of persistent connections per 176// host. Currently Chrome, Firefox, and IE8 have this value set at 6. Safari 177// uses 4, and Fasterfox (a plugin for Firefox that supposedly configures it to 178// run faster) uses 8. We would like to see how much of an effect this value has 179// on browsing. Too large a value might cause us to run into SYN flood detection 180// mechanisms. 181void BrowserMainParts::ConnectionFieldTrial() { 182 const FieldTrial::Probability kConnDivisor = 100; 183 const FieldTrial::Probability kConn16 = 10; // 10% probability 184 const FieldTrial::Probability kRemainingConn = 30; // 30% probability 185 186 scoped_refptr<FieldTrial> conn_trial = 187 new FieldTrial("ConnCountImpact", kConnDivisor); 188 189 const int conn_16 = conn_trial->AppendGroup("_conn_count_16", kConn16); 190 const int conn_4 = conn_trial->AppendGroup("_conn_count_4", kRemainingConn); 191 const int conn_8 = conn_trial->AppendGroup("_conn_count_8", kRemainingConn); 192 const int conn_6 = conn_trial->AppendGroup("_conn_count_6", 193 FieldTrial::kAllRemainingProbability); 194 195 const int conn_trial_grp = conn_trial->group(); 196 197 if (conn_trial_grp == conn_4) { 198 net::HttpNetworkSession::set_max_sockets_per_group(4); 199 } else if (conn_trial_grp == conn_6) { 200 // This (6) is the current default value. 201 net::HttpNetworkSession::set_max_sockets_per_group(6); 202 } else if (conn_trial_grp == conn_8) { 203 net::HttpNetworkSession::set_max_sockets_per_group(8); 204 } else if (conn_trial_grp == conn_16) { 205 net::HttpNetworkSession::set_max_sockets_per_group(16); 206 } else { 207 NOTREACHED(); 208 } 209} 210 211// A/B test for determining a value for unused socket timeout. Currently the 212// timeout defaults to 10 seconds. Having this value set too low won't allow us 213// to take advantage of idle sockets. Setting it to too high could possibly 214// result in more ERR_CONNECT_RESETs, requiring one RTT to receive the RST 215// packet and possibly another RTT to re-establish the connection. 216void BrowserMainParts::SocketTimeoutFieldTrial() { 217 const FieldTrial::Probability kIdleSktToDivisor = 100; // Idle socket timeout 218 const FieldTrial::Probability kSktToProb = 25; // 25% probability 219 220 scoped_refptr<FieldTrial> socket_timeout_trial = 221 new FieldTrial("IdleSktToImpact", kIdleSktToDivisor); 222 223 const int socket_timeout_5 = 224 socket_timeout_trial->AppendGroup("_idle_timeout_5", kSktToProb); 225 const int socket_timeout_10 = 226 socket_timeout_trial->AppendGroup("_idle_timeout_10", kSktToProb); 227 const int socket_timeout_20 = 228 socket_timeout_trial->AppendGroup("_idle_timeout_20", kSktToProb); 229 const int socket_timeout_60 = 230 socket_timeout_trial->AppendGroup("_idle_timeout_60", 231 FieldTrial::kAllRemainingProbability); 232 233 const int idle_to_trial_grp = socket_timeout_trial->group(); 234 235 if (idle_to_trial_grp == socket_timeout_5) { 236 net::ClientSocketPool::set_unused_idle_socket_timeout(5); 237 } else if (idle_to_trial_grp == socket_timeout_10) { 238 // This (10 seconds) is the current default value. 239 net::ClientSocketPool::set_unused_idle_socket_timeout(10); 240 } else if (idle_to_trial_grp == socket_timeout_20) { 241 net::ClientSocketPool::set_unused_idle_socket_timeout(20); 242 } else if (idle_to_trial_grp == socket_timeout_60) { 243 net::ClientSocketPool::set_unused_idle_socket_timeout(60); 244 } else { 245 NOTREACHED(); 246 } 247} 248 249// When --use-spdy not set, users will be in A/B test for spdy. 250// group A (npn_with_spdy): this means npn and spdy are enabled. In case server 251// supports spdy, browser will use spdy. 252// group B (npn_with_http): this means npn is enabled but spdy won't be used. 253// Http is still used for all requests. 254// default group: no npn or spdy is involved. The "old" non-spdy 255// chrome behavior. 256void BrowserMainParts::SpdyFieldTrial() { 257 bool is_spdy_trial = false; 258 if (parsed_command_line().HasSwitch(switches::kUseSpdy)) { 259 std::string spdy_mode = 260 parsed_command_line().GetSwitchValueASCII(switches::kUseSpdy); 261 net::HttpNetworkLayer::EnableSpdy(spdy_mode); 262 } else { 263 const FieldTrial::Probability kSpdyDivisor = 1000; 264 // To enable 100% npn_with_spdy, set npnhttp_probability = 0 and set 265 // npnspdy_probability = FieldTrial::kAllRemainingProbability. 266 // To collect stats, make sure that FieldTrial are distributed among 267 // all the three groups: 268 // npn_with_spdy : 50%, npn_with_http : 25%, default (no npn, no spdy): 25%. 269 // a. npn_with_spdy and default: these are used to collect stats for 270 // alternate protocol with spdy vs. no alternate protocol case. 271 // b. npn_with_spdy and npn_with_http: these are used to collect stats for 272 // https vs. https over spdy case. 273 FieldTrial::Probability npnhttp_probability = 250; 274 FieldTrial::Probability npnspdy_probability = 500; 275 scoped_refptr<FieldTrial> trial = 276 new FieldTrial("SpdyImpact", kSpdyDivisor); 277 // npn with only http support, no spdy. 278 int npn_http_grp = 279 trial->AppendGroup("_npn_with_http", npnhttp_probability); 280 // npn with spdy support. 281 int npn_spdy_grp = 282 trial->AppendGroup("_npn_with_spdy", npnspdy_probability); 283 int trial_grp = trial->group(); 284 if (trial_grp == npn_http_grp) { 285 is_spdy_trial = true; 286 net::HttpNetworkLayer::EnableSpdy("npn-http"); 287 } else if (trial_grp == npn_spdy_grp) { 288 is_spdy_trial = true; 289 net::HttpNetworkLayer::EnableSpdy("npn"); 290 } else { 291 CHECK(!is_spdy_trial); 292 } 293 } 294} 295 296// TODO(viettrungluu): move to platform-specific methods 297void BrowserMainParts::InitializeSSL() { 298 // Use NSS for SSL by default. 299#if defined(OS_MACOSX) 300 // The default client socket factory uses NSS for SSL by default on Mac. 301 if (parsed_command_line().HasSwitch(switches::kUseSystemSSL)) { 302 net::ClientSocketFactory::SetSSLClientSocketFactory( 303 net::SSLClientSocketMacFactory); 304 } else { 305 // We want to be sure to init NSPR on the main thread. 306 base::EnsureNSPRInit(); 307 } 308#elif defined(OS_WIN) 309 // Because of a build system issue (http://crbug.com/43461), the default 310 // client socket factory uses SChannel (the system SSL library) for SSL by 311 // default on Windows. 312 if (!parsed_command_line().HasSwitch(switches::kUseSystemSSL)) { 313 net::ClientSocketFactory::SetSSLClientSocketFactory( 314 net::SSLClientSocketNSSFactory); 315 // We want to be sure to init NSPR on the main thread. 316 base::EnsureNSPRInit(); 317 } 318#endif 319} 320 321// ----------------------------------------------------------------------------- 322// TODO(viettrungluu): move more/rest of BrowserMain() into above structure 323 324namespace { 325 326// This function provides some ways to test crash and assertion handling 327// behavior of the program. 328void HandleTestParameters(const CommandLine& command_line) { 329 // This parameter causes an assertion. 330 if (command_line.HasSwitch(switches::kBrowserAssertTest)) { 331 DCHECK(false); 332 } 333 334 // This parameter causes a null pointer crash (crash reporter trigger). 335 if (command_line.HasSwitch(switches::kBrowserCrashTest)) { 336 int* bad_pointer = NULL; 337 *bad_pointer = 0; 338 } 339 340#if defined(OS_CHROMEOS) 341 // Test loading libcros and exit. We return 0 if the library could be loaded, 342 // and 1 if it can't be. This is for validation that the library is installed 343 // and versioned properly for Chrome to find. 344 if (command_line.HasSwitch(switches::kTestLoadLibcros)) 345 exit(!chromeos::CrosLibrary::Get()->EnsureLoaded()); 346#endif 347} 348 349void RunUIMessageLoop(BrowserProcess* browser_process) { 350#if defined(TOOLKIT_VIEWS) 351 views::AcceleratorHandler accelerator_handler; 352 MessageLoopForUI::current()->Run(&accelerator_handler); 353#elif defined(USE_X11) 354 MessageLoopForUI::current()->Run(NULL); 355#elif defined(OS_POSIX) 356 MessageLoopForUI::current()->Run(); 357#endif 358} 359 360void AddFirstRunNewTabs(BrowserInit* browser_init, 361 const std::vector<GURL>& new_tabs) { 362 for (std::vector<GURL>::const_iterator it = new_tabs.begin(); 363 it != new_tabs.end(); ++it) { 364 if (it->is_valid()) 365 browser_init->AddFirstRunTab(*it); 366 } 367} 368 369#if defined(USE_LINUX_BREAKPAD) 370class GetLinuxDistroTask : public Task { 371 public: 372 explicit GetLinuxDistroTask() {} 373 374 virtual void Run() { 375 base::GetLinuxDistro(); // Initialize base::linux_distro if needed. 376 } 377 378 DISALLOW_COPY_AND_ASSIGN(GetLinuxDistroTask); 379}; 380#endif // USE_LINUX_BREAKPAD 381 382void InitializeNetworkOptions(const CommandLine& parsed_command_line) { 383 if (parsed_command_line.HasSwitch(switches::kEnableFileCookies)) { 384 // Enable cookie storage for file:// URLs. Must do this before the first 385 // Profile (and therefore the first CookieMonster) is created. 386 net::CookieMonster::EnableFileScheme(); 387 } 388 389 if (parsed_command_line.HasSwitch(switches::kFixedHttpPort)) { 390 net::HttpNetworkSession::set_fixed_http_port(StringToInt( 391 parsed_command_line.GetSwitchValueASCII(switches::kFixedHttpPort))); 392 } 393 394 if (parsed_command_line.HasSwitch(switches::kFixedHttpsPort)) { 395 net::HttpNetworkSession::set_fixed_https_port(StringToInt( 396 parsed_command_line.GetSwitchValueASCII(switches::kFixedHttpsPort))); 397 } 398 399 if (parsed_command_line.HasSwitch(switches::kIgnoreCertificateErrors)) 400 net::HttpNetworkTransaction::IgnoreCertificateErrors(true); 401 402 if (parsed_command_line.HasSwitch(switches::kHostRules)) 403 net::HttpNetworkTransaction::SetHostMappingRules( 404 parsed_command_line.GetSwitchValueASCII(switches::kHostRules)); 405 406 if (parsed_command_line.HasSwitch(switches::kMaxSpdySessionsPerDomain)) { 407 int value = StringToInt( 408 parsed_command_line.GetSwitchValueASCII( 409 switches::kMaxSpdySessionsPerDomain)); 410 net::SpdySessionPool::set_max_sessions_per_domain(value); 411 } 412} 413 414// Creates key child threads. We need to do this explicitly since 415// ChromeThread::PostTask silently deletes a posted task if the target message 416// loop isn't created. 417void CreateChildThreads(BrowserProcessImpl* process) { 418 process->db_thread(); 419 process->file_thread(); 420 process->process_launcher_thread(); 421 process->cache_thread(); 422 process->io_thread(); 423} 424 425// Returns the new local state object, guaranteed non-NULL. 426PrefService* InitializeLocalState(const CommandLine& parsed_command_line, 427 bool is_first_run) { 428 FilePath local_state_path; 429 PathService::Get(chrome::FILE_LOCAL_STATE, &local_state_path); 430 bool local_state_file_exists = file_util::PathExists(local_state_path); 431 432 // Load local state. This includes the application locale so we know which 433 // locale dll to load. 434 PrefService* local_state = g_browser_process->local_state(); 435 DCHECK(local_state); 436 437 // Initialize ResourceBundle which handles files loaded from external 438 // sources. This has to be done before uninstall code path and before prefs 439 // are registered. 440 local_state->RegisterStringPref(prefs::kApplicationLocale, ""); 441 local_state->RegisterBooleanPref(prefs::kMetricsReportingEnabled, 442 GoogleUpdateSettings::GetCollectStatsConsent()); 443 444 if (is_first_run) { 445#if defined(OS_WIN) 446 // During first run we read the google_update registry key to find what 447 // language the user selected when downloading the installer. This 448 // becomes our default language in the prefs. 449 // Other platforms obey the system locale. 450 std::wstring install_lang; 451 if (GoogleUpdateSettings::GetLanguage(&install_lang)) { 452 local_state->SetString(prefs::kApplicationLocale, 453 WideToASCII(install_lang)); 454 } 455#endif // defined(OS_WIN) 456 } 457 458 // If the local state file for the current profile doesn't exist and the 459 // parent profile command line flag is present, then we should inherit some 460 // local state from the parent profile. 461 // Checking that the local state file for the current profile doesn't exist 462 // is the most robust way to determine whether we need to inherit or not 463 // since the parent profile command line flag can be present even when the 464 // current profile is not a new one, and in that case we do not want to 465 // inherit and reset the user's setting. 466 if (!local_state_file_exists && 467 parsed_command_line.HasSwitch(switches::kParentProfile)) { 468 FilePath parent_profile = 469 parsed_command_line.GetSwitchValuePath(switches::kParentProfile); 470 scoped_ptr<PrefService> parent_local_state( 471 PrefService::CreatePrefService(parent_profile)); 472 parent_local_state->RegisterStringPref(prefs::kApplicationLocale, 473 std::string()); 474 // Right now, we only inherit the locale setting from the parent profile. 475 local_state->SetString( 476 prefs::kApplicationLocale, 477 parent_local_state->GetString(prefs::kApplicationLocale)); 478 } 479 480 return local_state; 481} 482 483// Windows-specific initialization code for the sandbox broker services. This 484// is just a NOP on non-Windows platforms to reduce ifdefs later on. 485void InitializeBrokerServices(const MainFunctionParams& parameters, 486 const CommandLine& parsed_command_line) { 487#if defined(OS_WIN) 488 sandbox::BrokerServices* broker_services = 489 parameters.sandbox_info_.BrokerServices(); 490 if (broker_services) { 491 sandbox::InitBrokerServices(broker_services); 492 if (!parsed_command_line.HasSwitch(switches::kNoSandbox)) { 493 bool use_winsta = !parsed_command_line.HasSwitch( 494 switches::kDisableAltWinstation); 495 // Precreate the desktop and window station used by the renderers. 496 sandbox::TargetPolicy* policy = broker_services->CreatePolicy(); 497 sandbox::ResultCode result = policy->CreateAlternateDesktop(use_winsta); 498 CHECK(sandbox::SBOX_ERROR_FAILED_TO_SWITCH_BACK_WINSTATION != result); 499 policy->Release(); 500 } 501 } 502#endif 503} 504 505// Initializes the metrics service with the configuration for this process, 506// returning the created service (guaranteed non-NULL). 507MetricsService* InitializeMetrics(const CommandLine& parsed_command_line, 508 const PrefService* local_state) { 509#if defined(OS_WIN) 510 if (InstallUtil::IsChromeFrameProcess()) 511 MetricsLog::set_version_extension("-F"); 512#elif defined(ARCH_CPU_64_BITS) 513 MetricsLog::set_version_extension("-64"); 514#endif // defined(OS_WIN) 515 516 MetricsService* metrics = g_browser_process->metrics_service(); 517 518 if (parsed_command_line.HasSwitch(switches::kMetricsRecordingOnly)) { 519 // If we're testing then we don't care what the user preference is, we turn 520 // on recording, but not reporting, otherwise tests fail. 521 metrics->StartRecordingOnly(); 522 } else { 523 // If the user permits metrics reporting with the checkbox in the 524 // prefs, we turn on recording. We disable metrics completely for 525 // non-official builds. 526#if defined(GOOGLE_CHROME_BUILD) 527 bool enabled = local_state->GetBoolean(prefs::kMetricsReportingEnabled); 528 metrics->SetUserPermitsUpload(enabled); 529 if (enabled) { 530 metrics->Start(); 531 chrome_browser_net_websocket_experiment:: 532 WebSocketExperimentRunner::Start(); 533 } 534#endif 535 } 536 537 return metrics; 538} 539 540// Initializes the profile, possibly doing some user prompting to pick a 541// fallback profile. Returns the newly created profile, or NULL if startup 542// should not continue. 543Profile* CreateProfile(const MainFunctionParams& parameters, 544 const FilePath& user_data_dir) { 545 Profile* profile = g_browser_process->profile_manager()->GetDefaultProfile( 546 user_data_dir); 547 if (profile) 548 return profile; 549 550#if defined(OS_WIN) 551 // Ideally, we should be able to run w/o access to disk. For now, we 552 // prompt the user to pick a different user-data-dir and restart chrome 553 // with the new dir. 554 // http://code.google.com/p/chromium/issues/detail?id=11510 555 FilePath new_user_data_dir = UserDataDirDialog::RunUserDataDirDialog( 556 user_data_dir); 557 if (!parameters.ui_task && browser_shutdown::delete_resources_on_shutdown) { 558 // Only delete the resources if we're not running tests. If we're running 559 // tests the resources need to be reused as many places in the UI cache 560 // SkBitmaps from the ResourceBundle. 561 ResourceBundle::CleanupSharedInstance(); 562 } 563 564 if (!new_user_data_dir.empty()) { 565 // Because of the way CommandLine parses, it's sufficient to append a new 566 // --user-data-dir switch. The last flag of the same name wins. 567 // TODO(tc): It would be nice to remove the flag we don't want, but that 568 // sounds risky if we parse differently than CommandLineToArgvW. 569 CommandLine new_command_line = parameters.command_line_; 570 new_command_line.AppendSwitchWithValue(switches::kUserDataDir, 571 new_user_data_dir.ToWStringHack()); 572 base::LaunchApp(new_command_line, false, false, NULL); 573 } 574#else 575 // TODO(port): fix this. See comments near the definition of 576 // user_data_dir. It is better to CHECK-fail here than it is to 577 // silently exit because of missing code in the above test. 578 CHECK(profile) << "Cannot get default profile."; 579#endif 580 581 return NULL; 582} 583 584#if defined(OS_WIN) 585 586// gfx::Font callbacks 587void AdjustUIFont(LOGFONT* logfont) { 588 l10n_util::AdjustUIFont(logfont); 589} 590 591int GetMinimumFontSize() { 592 return StringToInt(l10n_util::GetString(IDS_MINIMUM_UI_FONT_SIZE).c_str()); 593} 594 595#endif 596 597#if defined(TOOLKIT_GTK) 598void InitializeToolkit() { 599 // It is important for this to happen before the first run dialog, as it 600 // styles the dialog as well. 601 gtk_util::InitRCStyles(); 602} 603#elif defined(TOOLKIT_VIEWS) 604void InitializeToolkit() { 605 // The delegate needs to be set before any UI is created so that windows 606 // display the correct icon. 607 if (!views::ViewsDelegate::views_delegate) 608 views::ViewsDelegate::views_delegate = new ChromeViewsDelegate; 609 610#if defined(OS_WIN) 611 gfx::Font::adjust_font_callback = &AdjustUIFont; 612 gfx::Font::get_minimum_font_size_callback = &GetMinimumFontSize; 613 614 // Init common control sex. 615 INITCOMMONCONTROLSEX config; 616 config.dwSize = sizeof(config); 617 config.dwICC = ICC_WIN95_CLASSES; 618 InitCommonControlsEx(&config); 619#endif 620} 621#else 622void InitializeToolkit() { 623} 624#endif 625 626#if defined(OS_CHROMEOS) 627 628void OptionallyRunChromeOSLoginManager(const CommandLine& parsed_command_line) { 629 if (parsed_command_line.HasSwitch(switches::kLoginManager)) { 630 std::string first_screen = 631 parsed_command_line.GetSwitchValueASCII(switches::kLoginScreen); 632 std::string size_arg = 633 parsed_command_line.GetSwitchValueASCII( 634 switches::kLoginScreenSize); 635 gfx::Size size(0, 0); 636 // Allow the size of the login window to be set explicitly. If not set, 637 // default to the entire screen. This is mostly useful for testing. 638 if (size_arg.size()) { 639 std::vector<std::string> dimensions; 640 SplitString(size_arg, ',', &dimensions); 641 if (dimensions.size() == 2) 642 size.SetSize(StringToInt(dimensions[0]), StringToInt(dimensions[1])); 643 } 644 browser::ShowLoginWizard(first_screen, size); 645 } 646} 647 648bool OptionallyApplyServicesCustomizationFromCommandLine( 649 const CommandLine& parsed_command_line, 650 BrowserInit* browser_init) { 651 // For Chrome OS, we may need to fetch OEM partner's services customization 652 // manifest and apply the customizations. This happens on the very first run 653 // or if startup manifest is passed on the command line. 654 scoped_ptr<chromeos::ServicesCustomizationDocument> customization; 655 customization.reset(new chromeos::ServicesCustomizationDocument()); 656 bool manifest_loaded = false; 657 if (parsed_command_line.HasSwitch(switches::kServicesManifest)) { 658 // Load manifest from file specified by command line switch. 659 FilePath manifest_path = 660 parsed_command_line.GetSwitchValuePath(switches::kServicesManifest); 661 manifest_loaded = customization->LoadManifestFromFile(manifest_path); 662 DCHECK(manifest_loaded) << manifest_path.value(); 663 } 664 // If manifest was loaded successfully, apply the customizations. 665 if (manifest_loaded) { 666 browser_init->ApplyServicesCustomization(customization.get()); 667 } 668 return manifest_loaded; 669} 670 671#else 672 673void OptionallyRunChromeOSLoginManager(const CommandLine& parsed_command_line) { 674 // Dummy empty function for non-ChromeOS builds to avoid extra ifdefs below. 675} 676 677bool OptionallyApplyServicesCustomizationFromCommandLine( 678 const CommandLine& parsed_command_line, 679 BrowserInit* browser_init) { 680 // Dummy empty function for non-ChromeOS builds to avoid extra ifdefs below. 681 return false; 682} 683 684#endif // defined(OS_CHROMEOS) 685 686#if defined(OS_MACOSX) 687OSStatus KeychainCallback(SecKeychainEvent keychain_event, 688 SecKeychainCallbackInfo *info, void *context) { 689 return noErr; 690} 691#endif 692 693} // namespace 694 695#if defined(OS_WIN) 696#define DLLEXPORT __declspec(dllexport) 697 698// We use extern C for the prototype DLLEXPORT to avoid C++ name mangling. 699extern "C" { 700DLLEXPORT void __cdecl RelaunchChromeBrowserWithNewCommandLineIfNeeded(); 701} 702 703DLLEXPORT void __cdecl RelaunchChromeBrowserWithNewCommandLineIfNeeded() { 704 Upgrade::RelaunchChromeBrowserWithNewCommandLineIfNeeded(); 705} 706#endif 707 708// Main routine for running as the Browser process. 709int BrowserMain(const MainFunctionParams& parameters) { 710 scoped_ptr<BrowserMainParts> 711 parts(BrowserMainParts::CreateBrowserMainParts(parameters)); 712 713 parts->EarlyInitialization(); 714 715 // TODO(viettrungluu): put the remainder into BrowserMainParts 716 const CommandLine& parsed_command_line = parameters.command_line_; 717 base::ScopedNSAutoreleasePool* pool = parameters.autorelease_pool_; 718 719 // WARNING: If we get a WM_ENDSESSION objects created on the stack here 720 // are NOT deleted. If you need something to run during WM_ENDSESSION add it 721 // to browser_shutdown::Shutdown or BrowserProcess::EndSession. 722 723 // TODO(beng, brettw): someday, break this out into sub functions with well 724 // defined roles (e.g. pre/post-profile startup, etc). 725 726 // Do platform-specific things (such as finishing initializing Cocoa) 727 // prior to instantiating the message loop. This could be turned into a 728 // broadcast notification. 729 WillInitializeMainMessageLoop(parameters); 730 731 MessageLoop main_message_loop(MessageLoop::TYPE_UI); 732 733 SystemMonitor system_monitor; 734 HighResolutionTimerManager hi_res_timer_manager; 735 scoped_ptr<net::NetworkChangeNotifier> network_change_notifier( 736 net::NetworkChangeNotifier::Create()); 737 738 const char* kThreadName = "CrBrowserMain"; 739 PlatformThread::SetName(kThreadName); 740 main_message_loop.set_thread_name(kThreadName); 741 742 // Register the main thread by instantiating it, but don't call any methods. 743 ChromeThread main_thread(ChromeThread::UI, MessageLoop::current()); 744 745 // TODO(viettrungluu): temporary while I refactor BrowserMain() 746 parts->TemporaryPosix_1(); 747 748 FilePath user_data_dir; 749#if defined(OS_WIN) 750 PathService::Get(chrome::DIR_USER_DATA, &user_data_dir); 751#else 752 // Getting the user data dir can fail if the directory isn't 753 // creatable, for example; on Windows in code below we bring up a 754 // dialog prompting the user to pick a different directory. 755 // However, ProcessSingleton needs a real user_data_dir on Mac/Linux, 756 // so it's better to fail here than fail mysteriously elsewhere. 757 CHECK(PathService::Get(chrome::DIR_USER_DATA, &user_data_dir)) 758 << "Must be able to get user data directory!"; 759#endif 760 761 ProcessSingleton process_singleton(user_data_dir); 762 763 bool is_first_run = FirstRun::IsChromeFirstRun() || 764 parsed_command_line.HasSwitch(switches::kFirstRun); 765 766 scoped_ptr<BrowserProcessImpl> browser_process; 767 if (parsed_command_line.HasSwitch(switches::kImport) || 768 parsed_command_line.HasSwitch(switches::kImportFromFile)) { 769 // We use different BrowserProcess when importing so no GoogleURLTracker is 770 // instantiated (as it makes a URLRequest and we don't have an IO thread, 771 // see bug #1292702). 772 browser_process.reset(new FirstRunBrowserProcess(parsed_command_line)); 773 is_first_run = false; 774 } else { 775 browser_process.reset(new BrowserProcessImpl(parsed_command_line)); 776 } 777 778 // BrowserProcessImpl's constructor should set g_browser_process. 779 DCHECK(g_browser_process); 780 781 // This forces the TabCloseableStateWatcher to be created and, on chromeos, 782 // register for the notifications it needs to track the closeable state of 783 // tabs. 784 g_browser_process->tab_closeable_state_watcher(); 785 786#if defined(USE_LINUX_BREAKPAD) 787 // Needs to be called after we have chrome::DIR_USER_DATA and 788 // g_browser_process. 789 g_browser_process->file_thread()->message_loop()->PostTask(FROM_HERE, 790 new GetLinuxDistroTask()); 791 InitCrashReporter(); 792#endif 793 794 // The broker service initialization needs to run early because it will 795 // initialize the sandbox broker, which requires the process to swap its 796 // window station. During this time all the UI will be broken. This has to 797 // run before threads and windows are created. 798 InitializeBrokerServices(parameters, parsed_command_line); 799 800 PrefService* local_state = InitializeLocalState(parsed_command_line, 801 is_first_run); 802 803 InitializeToolkit(); // Must happen before we try to display any UI. 804 805 // If we're running tests (ui_task is non-null), then the ResourceBundle 806 // has already been initialized. 807 if (parameters.ui_task) { 808 g_browser_process->SetApplicationLocale("en-US"); 809 } else { 810 // Mac starts it earlier in WillInitializeMainMessageLoop (because 811 // it is needed when loading the MainMenu.nib and the language doesn't 812 // depend on anything since it comes from Cocoa. 813#if defined(OS_MACOSX) 814 g_browser_process->SetApplicationLocale(l10n_util::GetLocaleOverride()); 815#else 816 // On a POSIX OS other than ChromeOS, the parameter that is passed to the 817 // method InitSharedInstance is ignored. 818 std::string app_locale = ResourceBundle::InitSharedInstance( 819 ASCIIToWide(local_state->GetString(prefs::kApplicationLocale))); 820 g_browser_process->SetApplicationLocale(app_locale); 821 822 FilePath resources_pack_path; 823 PathService::Get(chrome::FILE_RESOURCES_PACK, &resources_pack_path); 824 ResourceBundle::AddDataPackToSharedInstance(resources_pack_path); 825#endif // !defined(OS_MACOSX) 826 } 827 828#if defined(OS_POSIX) && !defined(OS_MACOSX) 829 gtk_util::SetDefaultWindowIcon(); 830#endif 831 832 std::string try_chrome = 833 parsed_command_line.GetSwitchValueASCII(switches::kTryChromeAgain); 834 if (!try_chrome.empty()) { 835#if defined(OS_WIN) 836 Upgrade::TryResult answer = 837 Upgrade::ShowTryChromeDialog(StringToInt(try_chrome)); 838 if (answer == Upgrade::TD_NOT_NOW) 839 return ResultCodes::NORMAL_EXIT_CANCEL; 840 if (answer == Upgrade::TD_UNINSTALL_CHROME) 841 return ResultCodes::NORMAL_EXIT_EXP2; 842#else 843 // We don't support retention experiments on Mac or Linux. 844 return ResultCodes::NORMAL_EXIT; 845#endif // defined(OS_WIN) 846 } 847 848 BrowserInit browser_init; 849 850 // On first run, we need to process the predictor preferences before the 851 // browser's profile_manager object is created, but after ResourceBundle 852 // is initialized. 853 FirstRun::MasterPrefs master_prefs = { 0 }; 854 bool first_run_ui_bypass = false; // True to skip first run UI. 855 if (is_first_run) { 856 first_run_ui_bypass = 857 !FirstRun::ProcessMasterPreferences(user_data_dir, &master_prefs); 858 AddFirstRunNewTabs(&browser_init, master_prefs.new_tabs); 859 860 // If we are running in App mode, we do not want to show the importer 861 // (first run) UI. 862 if (!first_run_ui_bypass && 863 (parsed_command_line.HasSwitch(switches::kApp) || 864 parsed_command_line.HasSwitch(switches::kNoFirstRun))) 865 first_run_ui_bypass = true; 866 } 867 868 // TODO(viettrungluu): why don't we run this earlier? 869 if (!parsed_command_line.HasSwitch(switches::kNoErrorDialogs)) 870 WarnAboutMinimumSystemRequirements(); 871 872 InitializeNetworkOptions(parsed_command_line); 873 874 // Initialize histogram statistics gathering system. 875 StatisticsRecorder statistics; 876 877 // Initialize histogram synchronizer system. This is a singleton and is used 878 // for posting tasks via NewRunnableMethod. Its deleted when it goes out of 879 // scope. Even though NewRunnableMethod does AddRef and Release, the object 880 // will not be deleted after the Task is executed. 881 scoped_refptr<HistogramSynchronizer> histogram_synchronizer = 882 new HistogramSynchronizer(); 883 884 // Initialize the prefs of the local state. 885 browser::RegisterLocalState(local_state); 886 887 // Now that all preferences have been registered, set the install date 888 // for the uninstall metrics if this is our first run. This only actually 889 // gets used if the user has metrics reporting enabled at uninstall time. 890 int64 install_date = 891 local_state->GetInt64(prefs::kUninstallMetricsInstallDate); 892 if (install_date == 0) { 893 local_state->SetInt64(prefs::kUninstallMetricsInstallDate, 894 base::Time::Now().ToTimeT()); 895 } 896 897#if defined(OS_MACOSX) 898 // Get the Keychain API to register for distributed notifications on the main 899 // thread, which has a proper CFRunloop, instead of later on the I/O thread, 900 // which doesn't. This ensures those notifications will get delivered 901 // properly. See issue 37766. 902 // (Note that the callback mask here is empty. I don't want to register for 903 // any callbacks, I just want to initialize the mechanism.) 904 SecKeychainAddCallback(&KeychainCallback, 0, NULL); 905#endif 906 907 CreateChildThreads(browser_process.get()); 908 909#if defined(OS_CHROMEOS) 910 // Now that the file thread exists we can record our stats. 911 chromeos::BootTimesLoader::Get()->RecordChromeMainStats(); 912#endif 913 914 // Record last shutdown time into a histogram. 915 browser_shutdown::ReadLastShutdownInfo(); 916 917#if defined(OS_WIN) 918 // On Windows, we use our startup as an opportunity to do upgrade/uninstall 919 // tasks. Those care whether the browser is already running. On Linux/Mac, 920 // upgrade/uninstall happen separately. 921 bool already_running = Upgrade::IsBrowserAlreadyRunning(); 922 923 // If the command line specifies 'uninstall' then we need to work here 924 // unless we detect another chrome browser running. 925 if (parsed_command_line.HasSwitch(switches::kUninstall)) 926 return DoUninstallTasks(already_running); 927#endif 928 929 if (parsed_command_line.HasSwitch(switches::kHideIcons) || 930 parsed_command_line.HasSwitch(switches::kShowIcons)) 931 return HandleIconsCommands(parsed_command_line); 932 if (parsed_command_line.HasSwitch(switches::kMakeDefaultBrowser)) { 933 return ShellIntegration::SetAsDefaultBrowser() ? 934 ResultCodes::NORMAL_EXIT : ResultCodes::SHELL_INTEGRATION_FAILED; 935 } 936 937#if !defined(OS_MACOSX) 938 // In environments other than Mac OS X we support import of settings 939 // from other browsers. In case this process is a short-lived "import" 940 // process that another browser runs just to import the settings, we 941 // don't want to be checking for another browser process, by design. 942 if (!(parsed_command_line.HasSwitch(switches::kImport) || 943 parsed_command_line.HasSwitch(switches::kImportFromFile))) { 944#endif 945 // When another process is running, use that process instead of starting a 946 // new one. NotifyOtherProcess will currently give the other process up to 947 // 20 seconds to respond. Note that this needs to be done before we attempt 948 // to read the profile. 949 switch (process_singleton.NotifyOtherProcessOrCreate()) { 950 case ProcessSingleton::PROCESS_NONE: 951 // No process already running, fall through to starting a new one. 952 break; 953 954 case ProcessSingleton::PROCESS_NOTIFIED: 955#if defined(OS_POSIX) && !defined(OS_MACOSX) 956 printf("%s\n", base::SysWideToNativeMB( 957 l10n_util::GetString(IDS_USED_EXISTING_BROWSER)).c_str()); 958#endif 959 return ResultCodes::NORMAL_EXIT; 960 961 case ProcessSingleton::PROFILE_IN_USE: 962 return ResultCodes::PROFILE_IN_USE; 963 964 case ProcessSingleton::LOCK_ERROR: 965 LOG(ERROR) << "Failed to create a ProcessSingleton for your profile " 966 "directory. This means that running multiple instances " 967 "would start multiple browser processes rather than " 968 "opening a new window in the existing process. Aborting " 969 "now to avoid profile corruption."; 970 return ResultCodes::PROFILE_IN_USE; 971 972 default: 973 NOTREACHED(); 974 } 975#if !defined(OS_MACOSX) // closing brace for if 976 } 977#endif 978 979 // Profile creation ---------------------------------------------------------- 980 981#if defined(OS_CHROMEOS) 982 // Initialize the screen locker now so that it can receive 983 // LOGIN_USER_CHANGED notification from UserManager. 984 chromeos::ScreenLocker::InitClass(); 985 986 // This forces the ProfileManager to be created and register for the 987 // notification it needs to track the logged in user. 988 g_browser_process->profile_manager()->GetDefaultProfile(); 989 990 if (parsed_command_line.HasSwitch(switches::kLoginUser)) { 991 std::string username = 992 parsed_command_line.GetSwitchValueASCII(switches::kLoginUser); 993 LOG(INFO) << "Relaunching browser for user: " << username; 994 chromeos::UserManager::Get()->UserLoggedIn(username); 995 } 996#endif 997 998 Profile* profile = CreateProfile(parameters, user_data_dir); 999 if (!profile) 1000 return ResultCodes::NORMAL_EXIT; 1001 1002 // Post-profile init --------------------------------------------------------- 1003 1004 PrefService* user_prefs = profile->GetPrefs(); 1005 DCHECK(user_prefs); 1006 1007 // Tests should be able to tune login manager before showing it. 1008 // Thus only show login manager in normal (non-testing) mode. 1009 if (!parameters.ui_task) { 1010 OptionallyRunChromeOSLoginManager(parsed_command_line); 1011 } 1012 1013#if !defined(OS_MACOSX) 1014 // Importing other browser settings is done in a browser-like process 1015 // that exits when this task has finished. 1016 // TODO(port): Port to Mac 1017 if (parsed_command_line.HasSwitch(switches::kImport) || 1018 parsed_command_line.HasSwitch(switches::kImportFromFile)) { 1019 return FirstRun::ImportNow(profile, parsed_command_line); 1020 } 1021#endif 1022 1023#if defined(OS_WIN) 1024 // Do the tasks if chrome has been upgraded while it was last running. 1025 if (!already_running && Upgrade::DoUpgradeTasks(parsed_command_line)) 1026 return ResultCodes::NORMAL_EXIT; 1027#endif 1028 1029 // Check if there is any machine level Chrome installed on the current 1030 // machine. If yes and the current Chrome process is user level, we do not 1031 // allow the user level Chrome to run. So we notify the user and uninstall 1032 // user level Chrome. 1033 // Note this check should only happen here, after all the checks above 1034 // (uninstall, resource bundle initialization, other chrome browser 1035 // processes etc). 1036 if (CheckMachineLevelInstall()) 1037 return ResultCodes::MACHINE_LEVEL_INSTALL_EXISTS; 1038 1039 // Create the TranslateManager singleton. 1040 Singleton<TranslateManager>::get(); 1041 1042#if defined(OS_MACOSX) 1043 if (!parsed_command_line.HasSwitch(switches::kNoFirstRun)) { 1044 // Disk image installation is sort of a first-run task, so it shares the 1045 // kNoFirstRun switch. 1046 if (MaybeInstallFromDiskImage()) { 1047 // The application was installed and the installed copy has been 1048 // launched. This process is now obsolete. Exit. 1049 return ResultCodes::NORMAL_EXIT; 1050 } 1051 } 1052#endif 1053 1054 // Show the First Run UI if this is the first time Chrome has been run on 1055 // this computer, or we're being compelled to do so by a command line flag. 1056 // Note that this be done _after_ the PrefService is initialized and all 1057 // preferences are registered, since some of the code that the importer 1058 // touches reads preferences. 1059 if (is_first_run) { 1060 if (!first_run_ui_bypass) { 1061#if defined(OS_WIN) 1062 FirstRun::AutoImport(profile, 1063 master_prefs.homepage_defined, 1064 master_prefs.do_import_items, 1065 master_prefs.dont_import_items, 1066 master_prefs.run_search_engine_experiment, 1067 master_prefs.randomize_search_engine_experiment, 1068 &process_singleton); 1069#else 1070 if (!OpenFirstRunDialog(profile, 1071 master_prefs.homepage_defined, 1072 master_prefs.do_import_items, 1073 master_prefs.dont_import_items, 1074 master_prefs.run_search_engine_experiment, 1075 master_prefs.randomize_search_engine_experiment, 1076 &process_singleton)) { 1077 return ResultCodes::NORMAL_EXIT; 1078 } 1079#endif 1080#if defined(OS_POSIX) 1081 // On Windows, the download is tagged with enable/disable stats so there 1082 // is no need for this code. 1083 1084 // If stats reporting was turned on by the first run dialog then toggle 1085 // the pref. 1086 if (GoogleUpdateSettings::GetCollectStatsConsent()) 1087 local_state->SetBoolean(prefs::kMetricsReportingEnabled, true); 1088#endif // OS_POSIX 1089 } // if (!first_run_ui_bypass) 1090 1091 Browser::SetNewHomePagePrefs(user_prefs); 1092 } 1093 1094 // Sets things up so that if we crash from this point on, a dialog will 1095 // popup asking the user to restart chrome. It is done this late to avoid 1096 // testing against a bunch of special cases that are taken care early on. 1097 PrepareRestartOnCrashEnviroment(parsed_command_line); 1098 1099 // Initialize and maintain network predictor module, which handles DNS 1100 // pre-resolution, as well as TCP/IP connection pre-warming. 1101 // This also registers an observer to discard data when closing incognito 1102 // mode. 1103 chrome_browser_net::PredictorInit dns_prefetch( 1104 user_prefs, 1105 local_state, 1106 parsed_command_line.HasSwitch(switches::kEnablePreconnect), 1107 parsed_command_line.HasSwitch(switches::kPreconnectDespiteProxy)); 1108 1109#if defined(OS_WIN) 1110 win_util::ScopedCOMInitializer com_initializer; 1111 1112 // Init the RLZ library. This just binds the dll and schedules a task on the 1113 // file thread to be run sometime later. If this is the first run we record 1114 // the installation event. 1115 RLZTracker::InitRlzDelayed(is_first_run, master_prefs.ping_delay); 1116#endif 1117 1118 // Configure the network module so it has access to resources. 1119 net::NetModule::SetResourceProvider(chrome_common_net::NetResourceProvider); 1120 1121 // Register our global network handler for chrome:// and 1122 // chrome-extension:// URLs. 1123 RegisterURLRequestChromeJob(); 1124 RegisterExtensionProtocols(); 1125 RegisterMetadataURLRequestHandler(); 1126 1127 // If path to partner services customization document was passed on command 1128 // line, apply the customizations (Chrome OS only). 1129 // TODO(denisromanov): Remove this when not needed for testing. 1130 OptionallyApplyServicesCustomizationFromCommandLine(parsed_command_line, 1131 &browser_init); 1132 1133 // In unittest mode, this will do nothing. In normal mode, this will create 1134 // the global GoogleURLTracker and IntranetRedirectDetector instances, which 1135 // will promptly go to sleep for five and seven seconds, respectively (to 1136 // avoid slowing startup), and wake up afterwards to see if they should do 1137 // anything else. 1138 // 1139 // A simpler way of doing all this would be to have some function which could 1140 // give the time elapsed since startup, and simply have these objects check 1141 // that when asked to initialize themselves, but this doesn't seem to exist. 1142 // 1143 // These can't be created in the BrowserProcessImpl constructor because they 1144 // need to read prefs that get set after that runs. 1145 browser_process->google_url_tracker(); 1146 browser_process->intranet_redirect_detector(); 1147 1148 // Do initialize the plug-in service (and related preferences). 1149 PluginService::InitGlobalInstance(profile); 1150 1151 // Prepare for memory caching of SDCH dictionaries. 1152 // Perform A/B test to measure global impact of SDCH support. 1153 // Set up a field trial to see what disabling SDCH does to latency of page 1154 // layout globally. 1155 FieldTrial::Probability kSDCH_DIVISOR = 1000; 1156 FieldTrial::Probability kSDCH_DISABLE_PROBABILITY = 1; // 0.1% probability. 1157 scoped_refptr<FieldTrial> sdch_trial = 1158 new FieldTrial("GlobalSdch", kSDCH_DIVISOR); 1159 1160 // Use default of "" so that all domains are supported. 1161 std::string sdch_supported_domain(""); 1162 if (parsed_command_line.HasSwitch(switches::kSdchFilter)) { 1163 sdch_supported_domain = 1164 parsed_command_line.GetSwitchValueASCII(switches::kSdchFilter); 1165 } else { 1166 sdch_trial->AppendGroup("_global_disable_sdch", 1167 kSDCH_DISABLE_PROBABILITY); 1168 int sdch_enabled = sdch_trial->AppendGroup("_global_enable_sdch", 1169 FieldTrial::kAllRemainingProbability); 1170 if (sdch_enabled != sdch_trial->group()) 1171 sdch_supported_domain = "never_enabled_sdch_for_any_domain"; 1172 } 1173 1174 SdchManager sdch_manager; // Singleton database. 1175 sdch_manager.set_sdch_fetcher(new SdchDictionaryFetcher); 1176 sdch_manager.EnableSdchSupport(sdch_supported_domain); 1177 1178 MetricsService* metrics = InitializeMetrics(parsed_command_line, local_state); 1179 InstallJankometer(parsed_command_line); 1180 1181#if defined(OS_WIN) && !defined(GOOGLE_CHROME_BUILD) 1182 if (parsed_command_line.HasSwitch(switches::kDebugPrint)) { 1183 printing::PrintedDocument::set_debug_dump_path( 1184 parsed_command_line.GetSwitchValue(switches::kDebugPrint)); 1185 } 1186#endif 1187 1188 HandleTestParameters(parsed_command_line); 1189 RecordBreakpadStatusUMA(metrics); 1190 1191 // Stat the directory with the inspector's files so that we can know if we 1192 // should display the entry in the context menu or not. 1193 browser_process->CheckForInspectorFiles(); 1194 1195#if defined(OS_CHROMEOS) 1196 metrics->StartExternalMetrics(); 1197#endif 1198 1199 if (profile->GetExtensionsService()) { 1200 // This will initialize bookmarks. Call it after bookmark import is done. 1201 // See issue 40144. 1202 profile->GetExtensionsService()->InitEventRouters(); 1203 } 1204 1205#if defined(OS_WIN) 1206 // We check this here because if the profile is OTR (chromeos possibility) 1207 // it won't still be accessible after browser is destroyed. 1208 bool record_search_engine = is_first_run && !profile->IsOffTheRecord(); 1209#endif 1210 1211 // ChildProcess:: is a misnomer unless you consider context. Use 1212 // of --wait-for-debugger only makes sense when Chrome itself is a 1213 // child process (e.g. when launched by PyAuto). 1214 if (parsed_command_line.HasSwitch(switches::kWaitForDebugger)) { 1215 ChildProcess::WaitForDebugger(L"Browser"); 1216 } 1217 1218 int result_code = ResultCodes::NORMAL_EXIT; 1219 if (parameters.ui_task) { 1220 // We are in test mode. Run one task and enter the main message loop. 1221 if (pool) 1222 pool->Recycle(); 1223 parameters.ui_task->Run(); 1224 delete parameters.ui_task; 1225 } else { 1226 // We are in regular browser boot sequence. Open initial stabs and enter 1227 // the main message loop. 1228 if (browser_init.Start(parsed_command_line, std::wstring(), profile, 1229 &result_code)) { 1230#if (defined(OS_WIN) || defined(OS_LINUX)) && !defined(OS_CHROMEOS) 1231 // Initialize autoupdate timer. Timer callback costs basically nothing 1232 // when browser is not in persistent mode, so it's OK to let it ride on 1233 // the main thread. This needs to be done here because we don't want 1234 // to start the timer when Chrome is run inside a test harness. 1235 g_browser_process->StartAutoupdateTimer(); 1236#endif 1237 1238#if defined(OS_LINUX) && !defined(OS_CHROMEOS) 1239 // On Linux, the running exe will be updated if an upgrade becomes 1240 // available while the browser is running. We need to save the last 1241 // modified time of the exe, so we can compare to determine if there is 1242 // an upgrade while the browser is kept alive by a persistent extension. 1243 Upgrade::SaveLastModifiedTimeOfExe(); 1244#endif 1245 1246 // Record now as the last successful chrome start. 1247 GoogleUpdateSettings::SetLastRunTime(); 1248 // Call Recycle() here as late as possible, before going into the loop 1249 // because Start() will add things to it while creating the main window. 1250 if (pool) 1251 pool->Recycle(); 1252 RunUIMessageLoop(browser_process.get()); 1253 } 1254 } 1255 1256#if defined(OS_WIN) 1257 // If it's the first run, log the search engine chosen. We wait until 1258 // shutdown because otherwise we can't be sure the user has finished 1259 // selecting a search engine through the dialog reached from the first run 1260 // bubble link. 1261 if (FirstRun::InSearchExperimentLocale() && record_search_engine) { 1262 const TemplateURL* default_search_engine = 1263 profile->GetTemplateURLModel()->GetDefaultSearchProvider(); 1264 // Record the search engine chosen. 1265 if (master_prefs.run_search_engine_experiment) { 1266 UMA_HISTOGRAM_ENUMERATION( 1267 "Chrome.SearchSelectExperiment", 1268 TemplateURLPrepopulateData::GetSearchEngineType( 1269 default_search_engine), 1270 TemplateURLPrepopulateData::SEARCH_ENGINE_MAX); 1271 // If the selection has been randomized, also record the winner by slot. 1272 if (master_prefs.randomize_search_engine_experiment) { 1273 size_t engine_pos = profile->GetTemplateURLModel()-> 1274 GetSearchEngineDialogSlot(); 1275 if (engine_pos < 4) { 1276 std::string experiment_type = "Chrome.SearchSelectExperimentSlot"; 1277 // Nicer in UMA if slots are 1-based. 1278 experiment_type.push_back('1' + engine_pos); 1279 UMA_HISTOGRAM_ENUMERATION( 1280 experiment_type, 1281 TemplateURLPrepopulateData::GetSearchEngineType( 1282 default_search_engine), 1283 TemplateURLPrepopulateData::SEARCH_ENGINE_MAX); 1284 } else { 1285 NOTREACHED() << "Invalid search engine selection slot."; 1286 } 1287 } 1288 } else { 1289 UMA_HISTOGRAM_ENUMERATION( 1290 "Chrome.SearchSelectExempt", 1291 TemplateURLPrepopulateData::GetSearchEngineType( 1292 default_search_engine), 1293 TemplateURLPrepopulateData::SEARCH_ENGINE_MAX); 1294 } 1295 } 1296#endif 1297 1298 chrome_browser_net_websocket_experiment::WebSocketExperimentRunner::Stop(); 1299 1300 process_singleton.Cleanup(); 1301 1302 metrics->Stop(); 1303 1304 // browser_shutdown takes care of deleting browser_process, so we need to 1305 // release it. 1306 ignore_result(browser_process.release()); 1307 browser_shutdown::Shutdown(); 1308 1309 return result_code; 1310} 1311