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/browser_main.h" 6 7 #include <algorithm> 8 #include <string> 9 #include <vector> 10 11 #include "base/allocator/allocator_shim.h" 12 #include "base/at_exit.h" 13 #include "base/command_line.h" 14 #include "base/debug/trace_event.h" 15 #include "base/file_path.h" 16 #include "base/file_util.h" 17 #include "base/mac/scoped_nsautorelease_pool.h" 18 #include "base/metrics/field_trial.h" 19 #include "base/metrics/histogram.h" 20 #include "base/path_service.h" 21 #include "base/process_util.h" 22 #include "base/string_number_conversions.h" 23 #include "base/string_piece.h" 24 #include "base/string_split.h" 25 #include "base/string_util.h" 26 #include "base/sys_string_conversions.h" 27 #include "base/threading/platform_thread.h" 28 #include "base/threading/thread_restrictions.h" 29 #include "base/time.h" 30 #include "base/utf_string_conversions.h" 31 #include "base/values.h" 32 #include "build/build_config.h" 33 #include "chrome/browser/about_flags.h" 34 #include "chrome/browser/browser_main_win.h" 35 #include "chrome/browser/browser_process.h" 36 #include "chrome/browser/browser_process_impl.h" 37 #include "chrome/browser/browser_shutdown.h" 38 #include "chrome/browser/chrome_content_browser_client.h" 39 #include "chrome/browser/defaults.h" 40 #include "chrome/browser/extensions/extension_protocols.h" 41 #include "chrome/browser/extensions/extension_service.h" 42 #include "chrome/browser/extensions/extensions_startup.h" 43 #include "chrome/browser/first_run/first_run.h" 44 #include "chrome/browser/first_run/first_run_browser_process.h" 45 #include "chrome/browser/first_run/upgrade_util.h" 46 #include "chrome/browser/jankometer.h" 47 #include "chrome/browser/metrics/histogram_synchronizer.h" 48 #include "chrome/browser/metrics/metrics_log.h" 49 #include "chrome/browser/metrics/metrics_service.h" 50 #include "chrome/browser/metrics/thread_watcher.h" 51 #include "chrome/browser/net/blob_url_request_job_factory.h" 52 #include "chrome/browser/net/chrome_dns_cert_provenance_checker.h" 53 #include "chrome/browser/net/chrome_dns_cert_provenance_checker_factory.h" 54 #include "chrome/browser/net/file_system_url_request_job_factory.h" 55 #include "chrome/browser/net/metadata_url_request.h" 56 #include "chrome/browser/net/predictor_api.h" 57 #include "chrome/browser/net/sdch_dictionary_fetcher.h" 58 #include "chrome/browser/net/websocket_experiment/websocket_experiment_runner.h" 59 #include "chrome/browser/prefs/browser_prefs.h" 60 #include "chrome/browser/prefs/pref_service.h" 61 #include "chrome/browser/prefs/pref_value_store.h" 62 #include "chrome/browser/prerender/prerender_field_trial.h" 63 #include "chrome/browser/printing/cloud_print/cloud_print_proxy_service.h" 64 #include "chrome/browser/process_singleton.h" 65 #include "chrome/browser/profiles/profile.h" 66 #include "chrome/browser/profiles/profile_manager.h" 67 #include "chrome/browser/search_engines/search_engine_type.h" 68 #include "chrome/browser/search_engines/template_url.h" 69 #include "chrome/browser/search_engines/template_url_model.h" 70 #include "chrome/browser/service/service_process_control.h" 71 #include "chrome/browser/service/service_process_control_manager.h" 72 #include "chrome/browser/shell_integration.h" 73 #include "chrome/browser/translate/translate_manager.h" 74 #include "chrome/browser/ui/browser.h" 75 #include "chrome/browser/ui/browser_init.h" 76 #include "chrome/browser/ui/webui/chrome_url_data_manager_backend.h" 77 #include "chrome/browser/web_resource/gpu_blacklist_updater.h" 78 #include "chrome/common/chrome_constants.h" 79 #include "chrome/common/chrome_paths.h" 80 #include "chrome/common/chrome_switches.h" 81 #include "chrome/common/env_vars.h" 82 #include "chrome/common/json_pref_store.h" 83 #include "chrome/common/jstemplate_builder.h" 84 #include "chrome/common/logging_chrome.h" 85 #include "chrome/common/net/net_resource_provider.h" 86 #include "chrome/common/pref_names.h" 87 #include "chrome/common/profiling.h" 88 #include "chrome/installer/util/google_update_settings.h" 89 #include "content/browser/browser_thread.h" 90 #include "content/browser/plugin_service.h" 91 #include "content/browser/renderer_host/resource_dispatcher_host.h" 92 #include "content/common/child_process.h" 93 #include "content/common/content_client.h" 94 #include "content/common/hi_res_timer_manager.h" 95 #include "content/common/main_function_params.h" 96 #include "content/common/result_codes.h" 97 #include "grit/app_locale_settings.h" 98 #include "grit/chromium_strings.h" 99 #include "grit/generated_resources.h" 100 #include "grit/platform_locale_settings.h" 101 #include "net/base/cookie_monster.h" 102 #include "net/base/net_module.h" 103 #include "net/base/network_change_notifier.h" 104 #include "net/http/http_network_layer.h" 105 #include "net/http/http_stream_factory.h" 106 #include "net/socket/client_socket_pool_base.h" 107 #include "net/socket/client_socket_pool_manager.h" 108 #include "net/socket/tcp_client_socket.h" 109 #include "net/spdy/spdy_session.h" 110 #include "net/spdy/spdy_session_pool.h" 111 #include "net/url_request/url_request.h" 112 #include "net/url_request/url_request_throttler_manager.h" 113 #include "ui/base/l10n/l10n_util.h" 114 #include "ui/base/resource/resource_bundle.h" 115 #include "ui/base/system_monitor/system_monitor.h" 116 #include "ui/gfx/gl/gl_implementation.h" 117 #include "ui/gfx/gl/gl_switches.h" 118 119 #if defined(USE_LINUX_BREAKPAD) 120 #include "base/linux_util.h" 121 #include "chrome/app/breakpad_linux.h" 122 #endif 123 124 #if defined(OS_POSIX) && !defined(OS_MACOSX) 125 #include <dbus/dbus-glib.h> 126 127 #include "chrome/browser/browser_main_gtk.h" 128 #include "chrome/browser/ui/gtk/gtk_util.h" 129 #endif 130 131 #if defined(OS_LINUX) && !defined(OS_CHROMEOS) 132 #include "chrome/browser/first_run/upgrade_util_linux.h" 133 #endif 134 135 #if defined(OS_CHROMEOS) 136 #include "chrome/browser/chromeos/boot_times_loader.h" 137 #include "chrome/browser/chromeos/brightness_observer.h" 138 #include "chrome/browser/chromeos/cros/cros_library.h" 139 #include "chrome/browser/chromeos/cros/screen_lock_library.h" 140 #include "chrome/browser/chromeos/customization_document.h" 141 #include "chrome/browser/chromeos/external_metrics.h" 142 #include "chrome/browser/chromeos/login/authenticator.h" 143 #include "chrome/browser/chromeos/login/login_utils.h" 144 #include "chrome/browser/chromeos/login/ownership_service.h" 145 #include "chrome/browser/chromeos/login/screen_locker.h" 146 #include "chrome/browser/chromeos/login/user_manager.h" 147 #include "chrome/browser/chromeos/metrics_cros_settings_provider.h" 148 #include "chrome/browser/chromeos/net/network_change_notifier_chromeos.h" 149 #include "chrome/browser/chromeos/system_key_event_listener.h" 150 #include "chrome/browser/oom_priority_manager.h" 151 #include "chrome/browser/ui/views/browser_dialogs.h" 152 #endif 153 154 // TODO(port): several win-only methods have been pulled out of this, but 155 // BrowserMain() as a whole needs to be broken apart so that it's usable by 156 // other platforms. For now, it's just a stub. This is a serious work in 157 // progress and should not be taken as an indication of a real refactoring. 158 159 #if defined(OS_WIN) 160 #include <commctrl.h> 161 #include <shellapi.h> 162 #include <windows.h> 163 164 #include "app/win/scoped_com_initializer.h" 165 #include "base/win/windows_version.h" 166 #include "chrome/browser/browser_trial.h" 167 #include "chrome/browser/browser_util_win.h" 168 #include "chrome/browser/first_run/try_chrome_dialog_view.h" 169 #include "chrome/browser/first_run/upgrade_util_win.h" 170 #include "chrome/browser/metrics/user_metrics.h" 171 #include "chrome/browser/net/url_fixer_upper.h" 172 #include "chrome/browser/rlz/rlz.h" 173 #include "chrome/browser/ui/views/user_data_dir_dialog.h" 174 #include "chrome/common/sandbox_policy.h" 175 #include "chrome/installer/util/helper.h" 176 #include "chrome/installer/util/install_util.h" 177 #include "chrome/installer/util/shell_util.h" 178 #include "net/base/net_util.h" 179 #include "net/base/sdch_manager.h" 180 #include "printing/printed_document.h" 181 #include "sandbox/src/sandbox.h" 182 #include "ui/base/l10n/l10n_util_win.h" 183 #include "ui/gfx/platform_font_win.h" 184 #endif // defined(OS_WIN) 185 186 #if defined(OS_MACOSX) 187 #include <Security/Security.h> 188 189 #include "chrome/browser/cocoa/install_from_dmg.h" 190 #endif 191 192 #if defined(TOOLKIT_VIEWS) 193 #include "chrome/browser/ui/views/chrome_views_delegate.h" 194 #include "views/focus/accelerator_handler.h" 195 #if defined(TOOLKIT_USES_GTK) 196 #include "views/widget/widget_gtk.h" 197 #endif 198 #endif 199 200 #if defined(TOOLKIT_USES_GTK) 201 #include "ui/gfx/gtk_util.h" 202 #endif 203 204 #if defined(TOUCH_UI) 205 #include "views/widget/root_view.h" 206 #endif 207 208 // BrowserMainParts ------------------------------------------------------------ 209 210 BrowserMainParts::BrowserMainParts(const MainFunctionParams& parameters) 211 : parameters_(parameters), 212 parsed_command_line_(parameters.command_line_) { 213 } 214 215 BrowserMainParts::~BrowserMainParts() { 216 } 217 218 // BrowserMainParts: |EarlyInitialization()| and related ----------------------- 219 220 void BrowserMainParts::EarlyInitialization() { 221 PreEarlyInitialization(); 222 223 if (parsed_command_line().HasSwitch(switches::kEnableBenchmarking)) 224 base::FieldTrial::EnableBenchmarking(); 225 226 InitializeSSL(); 227 228 if (parsed_command_line().HasSwitch(switches::kEnableDNSSECCerts)) 229 net::SSLConfigService::EnableDNSSEC(); 230 if (parsed_command_line().HasSwitch(switches::kDisableSSLFalseStart)) 231 net::SSLConfigService::DisableFalseStart(); 232 // Disabled to stop people playing with it. 233 // if (parsed_command_line().HasSwitch(switches::kEnableSnapStart)) 234 // net::SSLConfigService::EnableSnapStart(); 235 if (parsed_command_line().HasSwitch( 236 switches::kEnableDNSCertProvenanceChecking)) { 237 net::SSLConfigService::EnableDNSCertProvenanceChecking(); 238 } 239 240 if (parsed_command_line().HasSwitch(switches::kEnableTcpFastOpen)) 241 net::set_tcp_fastopen_enabled(true); 242 243 PostEarlyInitialization(); 244 } 245 246 // This will be called after the command-line has been mutated by about:flags 247 void BrowserMainParts::SetupFieldTrials() { 248 // Note: make sure to call ConnectionFieldTrial() before 249 // ProxyConnectionsFieldTrial(). 250 ConnectionFieldTrial(); 251 SocketTimeoutFieldTrial(); 252 ProxyConnectionsFieldTrial(); 253 prerender::ConfigurePrefetchAndPrerender(parsed_command_line()); 254 SpdyFieldTrial(); 255 ConnectBackupJobsFieldTrial(); 256 SSLFalseStartFieldTrial(); 257 } 258 259 // This is an A/B test for the maximum number of persistent connections per 260 // host. Currently Chrome, Firefox, and IE8 have this value set at 6. Safari 261 // uses 4, and Fasterfox (a plugin for Firefox that supposedly configures it to 262 // run faster) uses 8. We would like to see how much of an effect this value has 263 // on browsing. Too large a value might cause us to run into SYN flood detection 264 // mechanisms. 265 void BrowserMainParts::ConnectionFieldTrial() { 266 const base::FieldTrial::Probability kConnectDivisor = 100; 267 const base::FieldTrial::Probability kConnectProbability = 1; // 1% prob. 268 269 // After June 30, 2011 builds, it will always be in default group. 270 scoped_refptr<base::FieldTrial> connect_trial( 271 new base::FieldTrial( 272 "ConnCountImpact", kConnectDivisor, "conn_count_6", 2011, 6, 30)); 273 274 // This (6) is the current default value. Having this group declared here 275 // makes it straightforward to modify |kConnectProbability| such that the same 276 // probability value will be assigned to all the other groups, while 277 // preserving the remainder of the of probability space to the default value. 278 const int connect_6 = connect_trial->kDefaultGroupNumber; 279 280 const int connect_5 = connect_trial->AppendGroup("conn_count_5", 281 kConnectProbability); 282 const int connect_7 = connect_trial->AppendGroup("conn_count_7", 283 kConnectProbability); 284 const int connect_8 = connect_trial->AppendGroup("conn_count_8", 285 kConnectProbability); 286 const int connect_9 = connect_trial->AppendGroup("conn_count_9", 287 kConnectProbability); 288 289 const int connect_trial_group = connect_trial->group(); 290 291 if (connect_trial_group == connect_5) { 292 net::ClientSocketPoolManager::set_max_sockets_per_group(5); 293 } else if (connect_trial_group == connect_6) { 294 net::ClientSocketPoolManager::set_max_sockets_per_group(6); 295 } else if (connect_trial_group == connect_7) { 296 net::ClientSocketPoolManager::set_max_sockets_per_group(7); 297 } else if (connect_trial_group == connect_8) { 298 net::ClientSocketPoolManager::set_max_sockets_per_group(8); 299 } else if (connect_trial_group == connect_9) { 300 net::ClientSocketPoolManager::set_max_sockets_per_group(9); 301 } else { 302 NOTREACHED(); 303 } 304 } 305 306 // A/B test for determining a value for unused socket timeout. Currently the 307 // timeout defaults to 10 seconds. Having this value set too low won't allow us 308 // to take advantage of idle sockets. Setting it to too high could possibly 309 // result in more ERR_CONNECT_RESETs, requiring one RTT to receive the RST 310 // packet and possibly another RTT to re-establish the connection. 311 void BrowserMainParts::SocketTimeoutFieldTrial() { 312 const base::FieldTrial::Probability kIdleSocketTimeoutDivisor = 100; 313 // 1% probability for all experimental settings. 314 const base::FieldTrial::Probability kSocketTimeoutProbability = 1; 315 316 // After June 30, 2011 builds, it will always be in default group. 317 scoped_refptr<base::FieldTrial> socket_timeout_trial( 318 new base::FieldTrial("IdleSktToImpact", kIdleSocketTimeoutDivisor, 319 "idle_timeout_60", 2011, 6, 30)); 320 const int socket_timeout_60 = socket_timeout_trial->kDefaultGroupNumber; 321 322 const int socket_timeout_5 = 323 socket_timeout_trial->AppendGroup("idle_timeout_5", 324 kSocketTimeoutProbability); 325 const int socket_timeout_10 = 326 socket_timeout_trial->AppendGroup("idle_timeout_10", 327 kSocketTimeoutProbability); 328 const int socket_timeout_20 = 329 socket_timeout_trial->AppendGroup("idle_timeout_20", 330 kSocketTimeoutProbability); 331 332 const int idle_to_trial_group = socket_timeout_trial->group(); 333 334 if (idle_to_trial_group == socket_timeout_5) { 335 net::ClientSocketPool::set_unused_idle_socket_timeout(5); 336 } else if (idle_to_trial_group == socket_timeout_10) { 337 net::ClientSocketPool::set_unused_idle_socket_timeout(10); 338 } else if (idle_to_trial_group == socket_timeout_20) { 339 net::ClientSocketPool::set_unused_idle_socket_timeout(20); 340 } else if (idle_to_trial_group == socket_timeout_60) { 341 net::ClientSocketPool::set_unused_idle_socket_timeout(60); 342 } else { 343 NOTREACHED(); 344 } 345 } 346 347 void BrowserMainParts::ProxyConnectionsFieldTrial() { 348 const base::FieldTrial::Probability kProxyConnectionsDivisor = 100; 349 // 25% probability 350 const base::FieldTrial::Probability kProxyConnectionProbability = 1; 351 352 // After June 30, 2011 builds, it will always be in default group. 353 scoped_refptr<base::FieldTrial> proxy_connection_trial( 354 new base::FieldTrial("ProxyConnectionImpact", kProxyConnectionsDivisor, 355 "proxy_connections_32", 2011, 6, 30)); 356 357 // This (32 connections per proxy server) is the current default value. 358 // Declaring it here allows us to easily re-assign the probability space while 359 // maintaining that the default group always has the remainder of the "share", 360 // which allows for cleaner and quicker changes down the line if needed. 361 const int proxy_connections_32 = proxy_connection_trial->kDefaultGroupNumber; 362 363 // The number of max sockets per group cannot be greater than the max number 364 // of sockets per proxy server. We tried using 8, and it can easily 365 // lead to total browser stalls. 366 const int proxy_connections_16 = 367 proxy_connection_trial->AppendGroup("proxy_connections_16", 368 kProxyConnectionProbability); 369 const int proxy_connections_64 = 370 proxy_connection_trial->AppendGroup("proxy_connections_64", 371 kProxyConnectionProbability); 372 373 const int proxy_connections_trial_group = proxy_connection_trial->group(); 374 375 if (proxy_connections_trial_group == proxy_connections_16) { 376 net::ClientSocketPoolManager::set_max_sockets_per_proxy_server(16); 377 } else if (proxy_connections_trial_group == proxy_connections_32) { 378 net::ClientSocketPoolManager::set_max_sockets_per_proxy_server(32); 379 } else if (proxy_connections_trial_group == proxy_connections_64) { 380 net::ClientSocketPoolManager::set_max_sockets_per_proxy_server(64); 381 } else { 382 NOTREACHED(); 383 } 384 } 385 386 // When --use-spdy not set, users will be in A/B test for spdy. 387 // group A (npn_with_spdy): this means npn and spdy are enabled. In case server 388 // supports spdy, browser will use spdy. 389 // group B (npn_with_http): this means npn is enabled but spdy won't be used. 390 // Http is still used for all requests. 391 // default group: no npn or spdy is involved. The "old" non-spdy 392 // chrome behavior. 393 void BrowserMainParts::SpdyFieldTrial() { 394 if (parsed_command_line().HasSwitch(switches::kUseSpdy)) { 395 std::string spdy_mode = 396 parsed_command_line().GetSwitchValueASCII(switches::kUseSpdy); 397 net::HttpNetworkLayer::EnableSpdy(spdy_mode); 398 } else { 399 #if !defined(OS_CHROMEOS) 400 bool is_spdy_trial = false; 401 const base::FieldTrial::Probability kSpdyDivisor = 100; 402 base::FieldTrial::Probability npnhttp_probability = 5; 403 404 // After June 30, 2011 builds, it will always be in default group. 405 scoped_refptr<base::FieldTrial> trial( 406 new base::FieldTrial( 407 "SpdyImpact", kSpdyDivisor, "npn_with_spdy", 2011, 6, 30)); 408 409 // npn with spdy support is the default. 410 int npn_spdy_grp = trial->kDefaultGroupNumber; 411 412 // npn with only http support, no spdy. 413 int npn_http_grp = trial->AppendGroup("npn_with_http", npnhttp_probability); 414 415 int trial_grp = trial->group(); 416 if (trial_grp == npn_http_grp) { 417 is_spdy_trial = true; 418 net::HttpNetworkLayer::EnableSpdy("npn-http"); 419 } else if (trial_grp == npn_spdy_grp) { 420 is_spdy_trial = true; 421 net::HttpNetworkLayer::EnableSpdy("npn"); 422 } else { 423 CHECK(!is_spdy_trial); 424 } 425 #else 426 // Always enable SPDY on Chrome OS 427 net::HttpNetworkLayer::EnableSpdy("npn"); 428 #endif // !defined(OS_CHROMEOS) 429 } 430 431 // Setup SPDY CWND Field trial. 432 const base::FieldTrial::Probability kSpdyCwndDivisor = 100; 433 const base::FieldTrial::Probability kSpdyCwnd16 = 20; // fixed at 16 434 const base::FieldTrial::Probability kSpdyCwnd10 = 20; // fixed at 10 435 const base::FieldTrial::Probability kSpdyCwndMin16 = 20; // no less than 16 436 const base::FieldTrial::Probability kSpdyCwndMin10 = 20; // no less than 10 437 438 // After June 30, 2011 builds, it will always be in default group 439 // (cwndDynamic). 440 scoped_refptr<base::FieldTrial> trial( 441 new base::FieldTrial( 442 "SpdyCwnd", kSpdyCwndDivisor, "cwndDynamic", 2011, 6, 30)); 443 444 trial->AppendGroup("cwnd10", kSpdyCwnd10); 445 trial->AppendGroup("cwnd16", kSpdyCwnd16); 446 trial->AppendGroup("cwndMin16", kSpdyCwndMin16); 447 trial->AppendGroup("cwndMin10", kSpdyCwndMin10); 448 449 if (parsed_command_line().HasSwitch(switches::kMaxSpdyConcurrentStreams)) { 450 int value = 0; 451 base::StringToInt(parsed_command_line().GetSwitchValueASCII( 452 switches::kMaxSpdyConcurrentStreams), 453 &value); 454 if (value > 0) 455 net::SpdySession::set_max_concurrent_streams(value); 456 } 457 } 458 459 void BrowserMainParts::SSLFalseStartFieldTrial() { 460 if (parsed_command_line().HasSwitch(switches::kDisableSSLFalseStart)) { 461 net::SSLConfigService::DisableFalseStart(); 462 return; 463 } 464 465 const base::FieldTrial::Probability kDivisor = 100; 466 base::FieldTrial::Probability falsestart_probability = 50; // 50/50 trial 467 468 // After July 30, 2011 builds, it will always be in default group. 469 scoped_refptr<base::FieldTrial> trial( 470 new base::FieldTrial( 471 "SSLFalseStart", kDivisor, "FalseStart_enabled", 2011, 7, 30)); 472 473 int disabled_group = trial->AppendGroup("FalseStart_disabled", 474 falsestart_probability); 475 476 int trial_grp = trial->group(); 477 if (trial_grp == disabled_group) 478 net::SSLConfigService::DisableFalseStart(); 479 } 480 481 482 // If neither --enable-connect-backup-jobs or --disable-connect-backup-jobs is 483 // specified, run an A/B test for automatically establishing backup TCP 484 // connections when a certain timeout value is exceeded. 485 void BrowserMainParts::ConnectBackupJobsFieldTrial() { 486 if (parsed_command_line().HasSwitch(switches::kEnableConnectBackupJobs)) { 487 net::internal::ClientSocketPoolBaseHelper::set_connect_backup_jobs_enabled( 488 true); 489 } else if (parsed_command_line().HasSwitch( 490 switches::kDisableConnectBackupJobs)) { 491 net::internal::ClientSocketPoolBaseHelper::set_connect_backup_jobs_enabled( 492 false); 493 } else { 494 const base::FieldTrial::Probability kConnectBackupJobsDivisor = 100; 495 // 1% probability. 496 const base::FieldTrial::Probability kConnectBackupJobsProbability = 1; 497 // After June 30, 2011 builds, it will always be in defaut group. 498 scoped_refptr<base::FieldTrial> trial( 499 new base::FieldTrial("ConnnectBackupJobs", 500 kConnectBackupJobsDivisor, "ConnectBackupJobsEnabled", 2011, 6, 501 30)); 502 const int connect_backup_jobs_enabled = trial->kDefaultGroupNumber; 503 trial->AppendGroup("ConnectBackupJobsDisabled", 504 kConnectBackupJobsProbability); 505 const int trial_group = trial->group(); 506 net::internal::ClientSocketPoolBaseHelper::set_connect_backup_jobs_enabled( 507 trial_group == connect_backup_jobs_enabled); 508 } 509 } 510 511 // BrowserMainParts: |MainMessageLoopStart()| and related ---------------------- 512 513 void BrowserMainParts::MainMessageLoopStart() { 514 PreMainMessageLoopStart(); 515 516 main_message_loop_.reset(new MessageLoop(MessageLoop::TYPE_UI)); 517 518 // TODO(viettrungluu): should these really go before setting the thread name? 519 system_monitor_.reset(new ui::SystemMonitor); 520 hi_res_timer_manager_.reset(new HighResolutionTimerManager); 521 #if defined(OS_CHROMEOS) 522 // TODO(zelidrag): We need to move cros library glue code outside of 523 // chrome/browser directory to avoid check_deps issues and then migrate 524 // NetworkChangeNotifierCros class to net/base where other OS implementations 525 // live. 526 network_change_notifier_.reset(new chromeos::NetworkChangeNotifierChromeos()); 527 #else 528 network_change_notifier_.reset(net::NetworkChangeNotifier::Create()); 529 #endif 530 InitializeMainThread(); 531 532 PostMainMessageLoopStart(); 533 Profiling::MainMessageLoopStarted(); 534 } 535 536 void BrowserMainParts::InitializeMainThread() { 537 const char* kThreadName = "CrBrowserMain"; 538 base::PlatformThread::SetName(kThreadName); 539 main_message_loop().set_thread_name(kThreadName); 540 541 // Register the main thread by instantiating it, but don't call any methods. 542 main_thread_.reset(new BrowserThread(BrowserThread::UI, 543 MessageLoop::current())); 544 } 545 546 // ----------------------------------------------------------------------------- 547 // TODO(viettrungluu): move more/rest of BrowserMain() into above structure 548 549 namespace { 550 551 // This function provides some ways to test crash and assertion handling 552 // behavior of the program. 553 void HandleTestParameters(const CommandLine& command_line) { 554 // This parameter causes an assertion. 555 if (command_line.HasSwitch(switches::kBrowserAssertTest)) { 556 DCHECK(false); 557 } 558 559 // This parameter causes a null pointer crash (crash reporter trigger). 560 if (command_line.HasSwitch(switches::kBrowserCrashTest)) { 561 int* bad_pointer = NULL; 562 *bad_pointer = 0; 563 } 564 565 #if defined(OS_CHROMEOS) 566 // Test loading libcros and exit. We return 0 if the library could be loaded, 567 // and 1 if it can't be. This is for validation that the library is installed 568 // and versioned properly for Chrome to find. 569 if (command_line.HasSwitch(switches::kTestLoadLibcros)) 570 exit(!chromeos::CrosLibrary::Get()->EnsureLoaded()); 571 #endif 572 } 573 574 void RunUIMessageLoop(BrowserProcess* browser_process) { 575 TRACE_EVENT_BEGIN("BrowserMain:MESSAGE_LOOP", 0, ""); 576 // This should be invoked as close to the start of the browser's 577 // UI thread message loop as possible to get a stable measurement 578 // across versions. 579 RecordBrowserStartupTime(); 580 581 // If the UI thread blocks, the whole UI is unresponsive. 582 // Do not allow disk IO from the UI thread. 583 base::ThreadRestrictions::SetIOAllowed(false); 584 585 #if defined(TOOLKIT_VIEWS) 586 views::AcceleratorHandler accelerator_handler; 587 MessageLoopForUI::current()->Run(&accelerator_handler); 588 #elif defined(USE_X11) 589 MessageLoopForUI::current()->Run(NULL); 590 #elif defined(OS_POSIX) 591 MessageLoopForUI::current()->Run(); 592 #endif 593 #if defined(OS_CHROMEOS) 594 chromeos::BootTimesLoader::Get()->AddLogoutTimeMarker("UIMessageLoopEnded", 595 true); 596 #endif 597 598 TRACE_EVENT_END("BrowserMain:MESSAGE_LOOP", 0, ""); 599 } 600 601 void AddFirstRunNewTabs(BrowserInit* browser_init, 602 const std::vector<GURL>& new_tabs) { 603 for (std::vector<GURL>::const_iterator it = new_tabs.begin(); 604 it != new_tabs.end(); ++it) { 605 if (it->is_valid()) 606 browser_init->AddFirstRunTab(*it); 607 } 608 } 609 610 #if defined(USE_LINUX_BREAKPAD) 611 class GetLinuxDistroTask : public Task { 612 public: 613 explicit GetLinuxDistroTask() {} 614 615 virtual void Run() { 616 base::GetLinuxDistro(); // Initialize base::linux_distro if needed. 617 } 618 619 DISALLOW_COPY_AND_ASSIGN(GetLinuxDistroTask); 620 }; 621 #endif // USE_LINUX_BREAKPAD 622 623 void InitializeNetworkOptions(const CommandLine& parsed_command_line) { 624 if (parsed_command_line.HasSwitch(switches::kEnableFileCookies)) { 625 // Enable cookie storage for file:// URLs. Must do this before the first 626 // Profile (and therefore the first CookieMonster) is created. 627 net::CookieMonster::EnableFileScheme(); 628 } 629 630 if (parsed_command_line.HasSwitch(switches::kIgnoreCertificateErrors)) 631 net::HttpStreamFactory::set_ignore_certificate_errors(true); 632 633 if (parsed_command_line.HasSwitch(switches::kHostRules)) 634 net::HttpStreamFactory::SetHostMappingRules( 635 parsed_command_line.GetSwitchValueASCII(switches::kHostRules)); 636 637 if (parsed_command_line.HasSwitch(switches::kEnableIPPooling)) 638 net::SpdySessionPool::enable_ip_pooling(true); 639 640 if (parsed_command_line.HasSwitch(switches::kDisableIPPooling)) 641 net::SpdySessionPool::enable_ip_pooling(false); 642 643 if (parsed_command_line.HasSwitch(switches::kMaxSpdySessionsPerDomain)) { 644 int value; 645 base::StringToInt(parsed_command_line.GetSwitchValueASCII( 646 switches::kMaxSpdySessionsPerDomain), 647 &value); 648 net::SpdySessionPool::set_max_sessions_per_domain(value); 649 } 650 651 net::URLRequestThrottlerManager::GetInstance()->set_enable_thread_checks( 652 true); 653 654 SetDnsCertProvenanceCheckerFactory(CreateChromeDnsCertProvenanceChecker); 655 } 656 657 // Creates key child threads. We need to do this explicitly since 658 // BrowserThread::PostTask silently deletes a posted task if the target message 659 // loop isn't created. 660 void CreateChildThreads(BrowserProcessImpl* process) { 661 process->db_thread(); 662 process->file_thread(); 663 process->process_launcher_thread(); 664 process->cache_thread(); 665 process->io_thread(); 666 // Create watchdog thread after creating all other threads because it will 667 // watch the other threads and they must be running. 668 process->watchdog_thread(); 669 } 670 671 // Returns the new local state object, guaranteed non-NULL. 672 PrefService* InitializeLocalState(const CommandLine& parsed_command_line, 673 bool is_first_run) { 674 FilePath local_state_path; 675 PathService::Get(chrome::FILE_LOCAL_STATE, &local_state_path); 676 bool local_state_file_exists = file_util::PathExists(local_state_path); 677 678 // Load local state. This includes the application locale so we know which 679 // locale dll to load. 680 PrefService* local_state = g_browser_process->local_state(); 681 DCHECK(local_state); 682 683 // TODO(brettw,*): this comment about ResourceBundle was here since 684 // initial commit. This comment seems unrelated, bit-rotten and 685 // a candidate for removal. 686 // Initialize ResourceBundle which handles files loaded from external 687 // sources. This has to be done before uninstall code path and before prefs 688 // are registered. 689 local_state->RegisterStringPref(prefs::kApplicationLocale, std::string()); 690 #if defined(OS_CHROMEOS) 691 local_state->RegisterStringPref(prefs::kOwnerLocale, std::string()); 692 local_state->RegisterStringPref(prefs::kHardwareKeyboardLayout, 693 std::string()); 694 #endif // defined(OS_CHROMEOS) 695 #if !defined(OS_CHROMEOS) 696 local_state->RegisterBooleanPref(prefs::kMetricsReportingEnabled, 697 GoogleUpdateSettings::GetCollectStatsConsent()); 698 #endif // !defined(OS_CHROMEOS) 699 700 if (is_first_run) { 701 #if defined(OS_WIN) 702 // During first run we read the google_update registry key to find what 703 // language the user selected when downloading the installer. This 704 // becomes our default language in the prefs. 705 // Other platforms obey the system locale. 706 std::wstring install_lang; 707 if (GoogleUpdateSettings::GetLanguage(&install_lang)) { 708 local_state->SetString(prefs::kApplicationLocale, 709 WideToASCII(install_lang)); 710 } 711 #endif // defined(OS_WIN) 712 } 713 714 // If the local state file for the current profile doesn't exist and the 715 // parent profile command line flag is present, then we should inherit some 716 // local state from the parent profile. 717 // Checking that the local state file for the current profile doesn't exist 718 // is the most robust way to determine whether we need to inherit or not 719 // since the parent profile command line flag can be present even when the 720 // current profile is not a new one, and in that case we do not want to 721 // inherit and reset the user's setting. 722 if (!local_state_file_exists && 723 parsed_command_line.HasSwitch(switches::kParentProfile)) { 724 FilePath parent_profile = 725 parsed_command_line.GetSwitchValuePath(switches::kParentProfile); 726 scoped_ptr<PrefService> parent_local_state( 727 PrefService::CreatePrefService(parent_profile, NULL, NULL)); 728 parent_local_state->RegisterStringPref(prefs::kApplicationLocale, 729 std::string()); 730 // Right now, we only inherit the locale setting from the parent profile. 731 local_state->SetString( 732 prefs::kApplicationLocale, 733 parent_local_state->GetString(prefs::kApplicationLocale)); 734 } 735 736 #if defined(OS_CHROMEOS) 737 if (parsed_command_line.HasSwitch(switches::kLoginManager)) { 738 std::string owner_locale = local_state->GetString(prefs::kOwnerLocale); 739 // Ensure that we start with owner's locale. 740 if (!owner_locale.empty() && 741 local_state->GetString(prefs::kApplicationLocale) != owner_locale && 742 !local_state->IsManagedPreference(prefs::kApplicationLocale)) { 743 local_state->SetString(prefs::kApplicationLocale, owner_locale); 744 local_state->ScheduleSavePersistentPrefs(); 745 } 746 } 747 #endif 748 749 return local_state; 750 } 751 752 // Windows-specific initialization code for the sandbox broker services. This 753 // is just a NOP on non-Windows platforms to reduce ifdefs later on. 754 void InitializeBrokerServices(const MainFunctionParams& parameters, 755 const CommandLine& parsed_command_line) { 756 #if defined(OS_WIN) 757 sandbox::BrokerServices* broker_services = 758 parameters.sandbox_info_.BrokerServices(); 759 if (broker_services) { 760 sandbox::InitBrokerServices(broker_services); 761 if (!parsed_command_line.HasSwitch(switches::kNoSandbox)) { 762 bool use_winsta = !parsed_command_line.HasSwitch( 763 switches::kDisableAltWinstation); 764 // Precreate the desktop and window station used by the renderers. 765 sandbox::TargetPolicy* policy = broker_services->CreatePolicy(); 766 sandbox::ResultCode result = policy->CreateAlternateDesktop(use_winsta); 767 CHECK(sandbox::SBOX_ERROR_FAILED_TO_SWITCH_BACK_WINSTATION != result); 768 policy->Release(); 769 } 770 } 771 #endif 772 } 773 774 // Initializes the metrics service with the configuration for this process, 775 // returning the created service (guaranteed non-NULL). 776 MetricsService* InitializeMetrics(const CommandLine& parsed_command_line, 777 const PrefService* local_state) { 778 #if defined(OS_WIN) 779 if (parsed_command_line.HasSwitch(switches::kChromeFrame)) 780 MetricsLog::set_version_extension("-F"); 781 #elif defined(ARCH_CPU_64_BITS) 782 MetricsLog::set_version_extension("-64"); 783 #endif // defined(OS_WIN) 784 785 MetricsService* metrics = g_browser_process->metrics_service(); 786 787 if (parsed_command_line.HasSwitch(switches::kMetricsRecordingOnly) || 788 parsed_command_line.HasSwitch(switches::kEnableBenchmarking)) { 789 // If we're testing then we don't care what the user preference is, we turn 790 // on recording, but not reporting, otherwise tests fail. 791 metrics->StartRecordingOnly(); 792 } else { 793 // If the user permits metrics reporting with the checkbox in the 794 // prefs, we turn on recording. We disable metrics completely for 795 // non-official builds. 796 #if defined(GOOGLE_CHROME_BUILD) 797 #if defined(OS_CHROMEOS) 798 bool enabled = chromeos::MetricsCrosSettingsProvider::GetMetricsStatus(); 799 #else 800 bool enabled = local_state->GetBoolean(prefs::kMetricsReportingEnabled); 801 #endif // #if defined(OS_CHROMEOS) 802 if (enabled) { 803 metrics->Start(); 804 chrome_browser_net_websocket_experiment:: 805 WebSocketExperimentRunner::Start(); 806 } 807 #endif 808 } 809 810 return metrics; 811 } 812 813 // Initializes the profile, possibly doing some user prompting to pick a 814 // fallback profile. Returns the newly created profile, or NULL if startup 815 // should not continue. 816 Profile* CreateProfile(const MainFunctionParams& parameters, 817 const FilePath& user_data_dir) { 818 Profile* profile = g_browser_process->profile_manager()->GetDefaultProfile( 819 user_data_dir); 820 if (profile) 821 return profile; 822 823 #if defined(OS_WIN) 824 // Ideally, we should be able to run w/o access to disk. For now, we 825 // prompt the user to pick a different user-data-dir and restart chrome 826 // with the new dir. 827 // http://code.google.com/p/chromium/issues/detail?id=11510 828 FilePath new_user_data_dir = UserDataDirDialog::RunUserDataDirDialog( 829 user_data_dir); 830 if (!parameters.ui_task && browser_shutdown::delete_resources_on_shutdown) { 831 // Only delete the resources if we're not running tests. If we're running 832 // tests the resources need to be reused as many places in the UI cache 833 // SkBitmaps from the ResourceBundle. 834 ResourceBundle::CleanupSharedInstance(); 835 } 836 837 if (!new_user_data_dir.empty()) { 838 // Because of the way CommandLine parses, it's sufficient to append a new 839 // --user-data-dir switch. The last flag of the same name wins. 840 // TODO(tc): It would be nice to remove the flag we don't want, but that 841 // sounds risky if we parse differently than CommandLineToArgvW. 842 CommandLine new_command_line = parameters.command_line_; 843 new_command_line.AppendSwitchPath(switches::kUserDataDir, 844 new_user_data_dir); 845 base::LaunchApp(new_command_line, false, false, NULL); 846 } 847 #else 848 // TODO(port): fix this. See comments near the definition of 849 // user_data_dir. It is better to CHECK-fail here than it is to 850 // silently exit because of missing code in the above test. 851 CHECK(profile) << "Cannot get default profile."; 852 #endif 853 854 return NULL; 855 } 856 857 #if defined(OS_WIN) 858 859 // gfx::Font callbacks 860 void AdjustUIFont(LOGFONT* logfont) { 861 l10n_util::AdjustUIFont(logfont); 862 } 863 864 int GetMinimumFontSize() { 865 int min_font_size; 866 base::StringToInt(l10n_util::GetStringUTF16(IDS_MINIMUM_UI_FONT_SIZE), 867 &min_font_size); 868 return min_font_size; 869 } 870 871 #endif 872 873 #if defined(TOOLKIT_USES_GTK) 874 static void GLibLogHandler(const gchar* log_domain, 875 GLogLevelFlags log_level, 876 const gchar* message, 877 gpointer userdata) { 878 if (!log_domain) 879 log_domain = "<unknown>"; 880 if (!message) 881 message = "<no message>"; 882 883 if (strstr(message, "Loading IM context type") || 884 strstr(message, "wrong ELF class: ELFCLASS64")) { 885 // http://crbug.com/9643 886 // Until we have a real 64-bit build or all of these 32-bit package issues 887 // are sorted out, don't fatal on ELF 32/64-bit mismatch warnings and don't 888 // spam the user with more than one of them. 889 static bool alerted = false; 890 if (!alerted) { 891 LOG(ERROR) << "Bug 9643: " << log_domain << ": " << message; 892 alerted = true; 893 } 894 } else if (strstr(message, "gtk_widget_size_allocate(): attempt to " 895 "allocate widget with width") && 896 !GTK_CHECK_VERSION(2, 16, 1)) { 897 // This warning only occurs in obsolete versions of GTK and is harmless. 898 // http://crbug.com/11133 899 } else if (strstr(message, "Theme file for default has no") || 900 strstr(message, "Theme directory") || 901 strstr(message, "theme pixmap")) { 902 LOG(ERROR) << "GTK theme error: " << message; 903 } else if (strstr(message, "gtk_drag_dest_leave: assertion")) { 904 LOG(ERROR) << "Drag destination deleted: http://crbug.com/18557"; 905 } else if (strstr(message, "Out of memory") && 906 strstr(log_domain, "<unknown>")) { 907 LOG(ERROR) << "DBus call timeout or out of memory: " 908 << "http://crosbug.com/15496"; 909 } else { 910 LOG(DFATAL) << log_domain << ": " << message; 911 } 912 } 913 914 static void SetUpGLibLogHandler() { 915 // Register GLib-handled assertions to go through our logging system. 916 const char* kLogDomains[] = { NULL, "Gtk", "Gdk", "GLib", "GLib-GObject" }; 917 for (size_t i = 0; i < arraysize(kLogDomains); i++) { 918 g_log_set_handler(kLogDomains[i], 919 static_cast<GLogLevelFlags>(G_LOG_FLAG_RECURSION | 920 G_LOG_FLAG_FATAL | 921 G_LOG_LEVEL_ERROR | 922 G_LOG_LEVEL_CRITICAL | 923 G_LOG_LEVEL_WARNING), 924 GLibLogHandler, 925 NULL); 926 } 927 } 928 #endif 929 930 void InitializeToolkit(const MainFunctionParams& parameters) { 931 // TODO(evan): this function is rather subtle, due to the variety 932 // of intersecting ifdefs we have. To keep it easy to follow, there 933 // are no #else branches on any #ifs. 934 935 #if defined(TOOLKIT_USES_GTK) 936 // We want to call g_thread_init(), but in some codepaths (tests) it 937 // is possible it has already been called. In older versions of 938 // GTK, it is an error to call g_thread_init twice; unfortunately, 939 // the API to tell whether it has been called already was also only 940 // added in a newer version of GTK! Thankfully, this non-intuitive 941 // check is actually equivalent and sufficient to work around the 942 // error. 943 if (!g_thread_supported()) 944 g_thread_init(NULL); 945 // Glib type system initialization. Needed at least for gconf, 946 // used in net/proxy/proxy_config_service_linux.cc. Most likely 947 // this is superfluous as gtk_init() ought to do this. It's 948 // definitely harmless, so retained as a reminder of this 949 // requirement for gconf. 950 g_type_init(); 951 // We use glib-dbus for geolocation and it's possible other libraries 952 // (e.g. gnome-keyring) will use it, so initialize its threading here 953 // as well. 954 dbus_g_thread_init(); 955 gfx::GtkInitFromCommandLine(parameters.command_line_); 956 SetUpGLibLogHandler(); 957 #endif 958 959 #if defined(TOOLKIT_GTK) 960 // It is important for this to happen before the first run dialog, as it 961 // styles the dialog as well. 962 gtk_util::InitRCStyles(); 963 #endif 964 965 #if defined(TOOLKIT_VIEWS) 966 // The delegate needs to be set before any UI is created so that windows 967 // display the correct icon. 968 if (!views::ViewsDelegate::views_delegate) 969 views::ViewsDelegate::views_delegate = new ChromeViewsDelegate; 970 971 #if defined(TOOLKIT_USES_GTK) 972 // TODO(beng): Move to WidgetImpl and implement on Windows too! 973 if (parameters.command_line_.HasSwitch(switches::kDebugViewsPaint)) 974 views::WidgetGtk::EnableDebugPaint(); 975 #endif 976 #endif 977 978 #if defined(OS_WIN) 979 gfx::PlatformFontWin::adjust_font_callback = &AdjustUIFont; 980 gfx::PlatformFontWin::get_minimum_font_size_callback = &GetMinimumFontSize; 981 982 // Init common control sex. 983 INITCOMMONCONTROLSEX config; 984 config.dwSize = sizeof(config); 985 config.dwICC = ICC_WIN95_CLASSES; 986 InitCommonControlsEx(&config); 987 #endif 988 } 989 990 #if defined(OS_CHROMEOS) 991 992 // Class is used to login using passed username and password. 993 // The instance will be deleted upon success or failure. 994 class StubLogin : public chromeos::LoginStatusConsumer, 995 public chromeos::LoginUtils::Delegate { 996 public: 997 explicit StubLogin(std::string username, std::string password) { 998 authenticator_ = chromeos::LoginUtils::Get()->CreateAuthenticator(this); 999 authenticator_.get()->AuthenticateToLogin( 1000 g_browser_process->profile_manager()->GetDefaultProfile(), 1001 username, 1002 password, 1003 std::string(), 1004 std::string()); 1005 } 1006 1007 void OnLoginFailure(const chromeos::LoginFailure& error) { 1008 LOG(ERROR) << "Login Failure: " << error.GetErrorString(); 1009 delete this; 1010 } 1011 1012 void OnLoginSuccess(const std::string& username, 1013 const std::string& password, 1014 const GaiaAuthConsumer::ClientLoginResult& credentials, 1015 bool pending_requests) { 1016 // Will call OnProfilePrepared in the end. 1017 chromeos::LoginUtils::Get()->PrepareProfile(username, 1018 password, 1019 credentials, 1020 pending_requests, 1021 this); 1022 } 1023 1024 // LoginUtils::Delegate implementation: 1025 virtual void OnProfilePrepared(Profile* profile) { 1026 chromeos::LoginUtils::DoBrowserLaunch(profile); 1027 delete this; 1028 } 1029 1030 scoped_refptr<chromeos::Authenticator> authenticator_; 1031 }; 1032 1033 void OptionallyRunChromeOSLoginManager(const CommandLine& parsed_command_line) { 1034 if (parsed_command_line.HasSwitch(switches::kLoginManager)) { 1035 std::string first_screen = 1036 parsed_command_line.GetSwitchValueASCII(switches::kLoginScreen); 1037 std::string size_arg = 1038 parsed_command_line.GetSwitchValueASCII( 1039 switches::kLoginScreenSize); 1040 gfx::Size size(0, 0); 1041 // Allow the size of the login window to be set explicitly. If not set, 1042 // default to the entire screen. This is mostly useful for testing. 1043 if (size_arg.size()) { 1044 std::vector<std::string> dimensions; 1045 base::SplitString(size_arg, ',', &dimensions); 1046 if (dimensions.size() == 2) { 1047 int width, height; 1048 if (base::StringToInt(dimensions[0], &width) && 1049 base::StringToInt(dimensions[1], &height)) 1050 size.SetSize(width, height); 1051 } 1052 } 1053 browser::ShowLoginWizard(first_screen, size); 1054 } else if (parsed_command_line.HasSwitch(switches::kLoginUser) && 1055 parsed_command_line.HasSwitch(switches::kLoginPassword)) { 1056 chromeos::BootTimesLoader::Get()->RecordLoginAttempted(); 1057 new StubLogin( 1058 parsed_command_line.GetSwitchValueASCII(switches::kLoginUser), 1059 parsed_command_line.GetSwitchValueASCII(switches::kLoginPassword)); 1060 } 1061 } 1062 1063 #else 1064 1065 void OptionallyRunChromeOSLoginManager(const CommandLine& parsed_command_line) { 1066 // Dummy empty function for non-ChromeOS builds to avoid extra ifdefs below. 1067 } 1068 1069 #endif // defined(OS_CHROMEOS) 1070 1071 #if defined(OS_MACOSX) 1072 OSStatus KeychainCallback(SecKeychainEvent keychain_event, 1073 SecKeychainCallbackInfo *info, void *context) { 1074 return noErr; 1075 } 1076 #endif 1077 1078 } // namespace 1079 1080 #if defined(OS_CHROMEOS) 1081 // Allows authenticator to be invoked without adding refcounting. The instances 1082 // will delete themselves upon completion. 1083 DISABLE_RUNNABLE_METHOD_REFCOUNT(StubLogin); 1084 #endif 1085 1086 #if defined(OS_WIN) 1087 #define DLLEXPORT __declspec(dllexport) 1088 1089 // We use extern C for the prototype DLLEXPORT to avoid C++ name mangling. 1090 extern "C" { 1091 DLLEXPORT void __cdecl RelaunchChromeBrowserWithNewCommandLineIfNeeded(); 1092 } 1093 1094 DLLEXPORT void __cdecl RelaunchChromeBrowserWithNewCommandLineIfNeeded() { 1095 // Need an instance of AtExitManager to handle singleton creations and 1096 // deletions. We need this new instance because, the old instance created 1097 // in ChromeMain() got destructed when the function returned. 1098 base::AtExitManager exit_manager; 1099 upgrade_util::RelaunchChromeBrowserWithNewCommandLineIfNeeded(); 1100 } 1101 #endif 1102 1103 #if defined(USE_LINUX_BREAKPAD) 1104 bool IsMetricsReportingEnabled(const PrefService* local_state) { 1105 // Check whether we should initialize the crash reporter. It may be disabled 1106 // through configuration policy or user preference. 1107 // The kHeadless environment variable overrides the decision, but only if the 1108 // crash service is under control of the user. It is used by QA testing 1109 // infrastructure to switch on generation of crash reports. 1110 #if defined(OS_CHROMEOS) 1111 bool breakpad_enabled = 1112 chromeos::MetricsCrosSettingsProvider::GetMetricsStatus(); 1113 if (!breakpad_enabled) 1114 breakpad_enabled = getenv(env_vars::kHeadless) != NULL; 1115 #else 1116 const PrefService::Preference* metrics_reporting_enabled = 1117 local_state->FindPreference(prefs::kMetricsReportingEnabled); 1118 CHECK(metrics_reporting_enabled); 1119 bool breakpad_enabled = 1120 local_state->GetBoolean(prefs::kMetricsReportingEnabled); 1121 if (!breakpad_enabled && metrics_reporting_enabled->IsUserModifiable()) 1122 breakpad_enabled = getenv(env_vars::kHeadless) != NULL; 1123 #endif // #if defined(OS_CHROMEOS) 1124 return breakpad_enabled; 1125 } 1126 #endif // #if defined(USE_LINUX_BREAKPAD) 1127 1128 // Main routine for running as the Browser process. 1129 int BrowserMain(const MainFunctionParams& parameters) { 1130 TRACE_EVENT_BEGIN("BrowserMain", 0, ""); 1131 1132 // If we're running tests (ui_task is non-null). 1133 if (parameters.ui_task) 1134 browser_defaults::enable_help_app = false; 1135 1136 scoped_ptr<BrowserMainParts> 1137 parts(BrowserMainParts::CreateBrowserMainParts(parameters)); 1138 1139 parts->EarlyInitialization(); 1140 1141 // Must happen before we try to use a message loop or display any UI. 1142 InitializeToolkit(parameters); 1143 1144 parts->MainMessageLoopStart(); 1145 1146 // WARNING: If we get a WM_ENDSESSION, objects created on the stack here 1147 // are NOT deleted. If you need something to run during WM_ENDSESSION add it 1148 // to browser_shutdown::Shutdown or BrowserProcess::EndSession. 1149 1150 // !!!!!!!!!! READ ME !!!!!!!!!! 1151 // I (viettrungluu) am in the process of refactoring |BrowserMain()|. If you 1152 // need to add something above this comment, read the documentation in 1153 // browser_main.h. If you need to add something below, please do the 1154 // following: 1155 // - Figure out where you should add your code. Do NOT just pick a random 1156 // location "which works". 1157 // - Document the dependencies apart from compile-time-checkable ones. What 1158 // must happen before your new code is executed? Does your new code need to 1159 // run before something else? Are there performance reasons for executing 1160 // your code at that point? 1161 // - If you need to create a (persistent) object, heap allocate it and keep a 1162 // |scoped_ptr| to it rather than allocating it on the stack. Otherwise 1163 // I'll have to convert your code when I refactor. 1164 // - Unless your new code is just a couple of lines, factor it out into a 1165 // function with a well-defined purpose. Do NOT just add it inline in 1166 // |BrowserMain()|. 1167 // Thanks! 1168 1169 // TODO(viettrungluu): put the remainder into BrowserMainParts 1170 const CommandLine& parsed_command_line = parameters.command_line_; 1171 base::mac::ScopedNSAutoreleasePool* pool = parameters.autorelease_pool_; 1172 1173 #if defined(OS_WIN) && !defined(NO_TCMALLOC) 1174 // When linking shared libraries, NO_TCMALLOC is defined, and dynamic 1175 // allocator selection is not supported. 1176 1177 // Make this call before going multithreaded, or spawning any subprocesses. 1178 base::allocator::SetupSubprocessAllocator(); 1179 #endif // OS_WIN 1180 1181 FilePath user_data_dir; 1182 #if defined(OS_WIN) 1183 PathService::Get(chrome::DIR_USER_DATA, &user_data_dir); 1184 #else 1185 // Getting the user data dir can fail if the directory isn't 1186 // creatable, for example; on Windows in code below we bring up a 1187 // dialog prompting the user to pick a different directory. 1188 // However, ProcessSingleton needs a real user_data_dir on Mac/Linux, 1189 // so it's better to fail here than fail mysteriously elsewhere. 1190 CHECK(PathService::Get(chrome::DIR_USER_DATA, &user_data_dir)) 1191 << "Must be able to get user data directory!"; 1192 #endif 1193 1194 ProcessSingleton process_singleton(user_data_dir); 1195 1196 bool is_first_run = FirstRun::IsChromeFirstRun() || 1197 parsed_command_line.HasSwitch(switches::kFirstRun); 1198 1199 scoped_ptr<BrowserProcessImpl> browser_process; 1200 if (parsed_command_line.HasSwitch(switches::kImport) || 1201 parsed_command_line.HasSwitch(switches::kImportFromFile)) { 1202 // We use different BrowserProcess when importing so no GoogleURLTracker is 1203 // instantiated (as it makes a net::URLRequest and we don't have an IO 1204 // thread, see bug #1292702). 1205 browser_process.reset(new FirstRunBrowserProcess(parsed_command_line)); 1206 is_first_run = false; 1207 } else { 1208 browser_process.reset(new BrowserProcessImpl(parsed_command_line)); 1209 } 1210 1211 // BrowserProcessImpl's constructor should set g_browser_process. 1212 DCHECK(g_browser_process); 1213 1214 // This forces the TabCloseableStateWatcher to be created and, on chromeos, 1215 // register for the notifications it needs to track the closeable state of 1216 // tabs. 1217 g_browser_process->tab_closeable_state_watcher(); 1218 1219 // The broker service initialization needs to run early because it will 1220 // initialize the sandbox broker, which requires the process to swap its 1221 // window station. During this time all the UI will be broken. This has to 1222 // run before threads and windows are created. 1223 InitializeBrokerServices(parameters, parsed_command_line); 1224 1225 // Initialize histogram statistics gathering system. 1226 base::StatisticsRecorder statistics; 1227 1228 PrefService* local_state = InitializeLocalState(parsed_command_line, 1229 is_first_run); 1230 1231 #if defined(USE_LINUX_BREAKPAD) 1232 // Needs to be called after we have chrome::DIR_USER_DATA and 1233 // g_browser_process. 1234 g_browser_process->file_thread()->message_loop()->PostTask(FROM_HERE, 1235 new GetLinuxDistroTask()); 1236 1237 if (IsMetricsReportingEnabled(local_state)) 1238 InitCrashReporter(); 1239 #endif 1240 1241 // If we're running tests (ui_task is non-null), then the ResourceBundle 1242 // has already been initialized. 1243 if (parameters.ui_task) { 1244 g_browser_process->SetApplicationLocale("en-US"); 1245 } else { 1246 // Mac starts it earlier in |PreMainMessageLoopStart()| (because it is 1247 // needed when loading the MainMenu.nib and the language doesn't depend on 1248 // anything since it comes from Cocoa. 1249 #if defined(OS_MACOSX) 1250 g_browser_process->SetApplicationLocale(l10n_util::GetLocaleOverride()); 1251 #else 1252 const std::string locale = 1253 local_state->GetString(prefs::kApplicationLocale); 1254 // On a POSIX OS other than ChromeOS, the parameter that is passed to the 1255 // method InitSharedInstance is ignored. 1256 const std::string loaded_locale = 1257 ResourceBundle::InitSharedInstance(locale); 1258 CHECK(!loaded_locale.empty()) << "Locale could not be found for " << locale; 1259 g_browser_process->SetApplicationLocale(loaded_locale); 1260 1261 FilePath resources_pack_path; 1262 PathService::Get(chrome::FILE_RESOURCES_PACK, &resources_pack_path); 1263 ResourceBundle::AddDataPackToSharedInstance(resources_pack_path); 1264 #endif // defined(OS_MACOSX) 1265 } 1266 1267 #if defined(TOOLKIT_GTK) 1268 g_set_application_name(l10n_util::GetStringUTF8(IDS_PRODUCT_NAME).c_str()); 1269 #endif 1270 1271 std::string try_chrome = 1272 parsed_command_line.GetSwitchValueASCII(switches::kTryChromeAgain); 1273 if (!try_chrome.empty()) { 1274 #if defined(OS_WIN) 1275 // Setup.exe has determined that we need to run a retention experiment 1276 // and has lauched chrome to show the experiment UI. 1277 if (process_singleton.FoundOtherProcessWindow()) { 1278 // It seems that we don't need to run the experiment since chrome 1279 // in the same profile is already running. 1280 VLOG(1) << "Retention experiment not required"; 1281 return TryChromeDialogView::NOT_NOW; 1282 } 1283 int try_chrome_int; 1284 base::StringToInt(try_chrome, &try_chrome_int); 1285 TryChromeDialogView::Result answer = 1286 TryChromeDialogView::Show(try_chrome_int, &process_singleton); 1287 if (answer == TryChromeDialogView::NOT_NOW) 1288 return ResultCodes::NORMAL_EXIT_CANCEL; 1289 if (answer == TryChromeDialogView::UNINSTALL_CHROME) 1290 return ResultCodes::NORMAL_EXIT_EXP2; 1291 #else 1292 // We don't support retention experiments on Mac or Linux. 1293 return ResultCodes::NORMAL_EXIT; 1294 #endif // defined(OS_WIN) 1295 } 1296 1297 BrowserInit browser_init; 1298 1299 // On first run, we need to process the predictor preferences before the 1300 // browser's profile_manager object is created, but after ResourceBundle 1301 // is initialized. 1302 FirstRun::MasterPrefs master_prefs; 1303 bool first_run_ui_bypass = false; // True to skip first run UI. 1304 if (is_first_run) { 1305 first_run_ui_bypass = 1306 !FirstRun::ProcessMasterPreferences(user_data_dir, &master_prefs); 1307 AddFirstRunNewTabs(&browser_init, master_prefs.new_tabs); 1308 1309 // If we are running in App mode, we do not want to show the importer 1310 // (first run) UI. 1311 if (!first_run_ui_bypass && 1312 (parsed_command_line.HasSwitch(switches::kApp) || 1313 parsed_command_line.HasSwitch(switches::kAppId) || 1314 parsed_command_line.HasSwitch(switches::kNoFirstRun))) 1315 first_run_ui_bypass = true; 1316 } 1317 1318 // TODO(viettrungluu): why don't we run this earlier? 1319 if (!parsed_command_line.HasSwitch(switches::kNoErrorDialogs)) 1320 WarnAboutMinimumSystemRequirements(); 1321 1322 InitializeNetworkOptions(parsed_command_line); 1323 1324 // Initialize histogram synchronizer system. This is a singleton and is used 1325 // for posting tasks via NewRunnableMethod. Its deleted when it goes out of 1326 // scope. Even though NewRunnableMethod does AddRef and Release, the object 1327 // will not be deleted after the Task is executed. 1328 scoped_refptr<HistogramSynchronizer> histogram_synchronizer( 1329 new HistogramSynchronizer()); 1330 1331 // Initialize thread watcher system. This is a singleton and is used by 1332 // WatchDogThread to keep track of information about threads that are being 1333 // watched. 1334 scoped_ptr<ThreadWatcherList> thread_watcher_list(new ThreadWatcherList()); 1335 1336 // Initialize the prefs of the local state. 1337 browser::RegisterLocalState(local_state); 1338 1339 // Convert active labs into switches. Modifies the current command line. 1340 about_flags::ConvertFlagsToSwitches(local_state, 1341 CommandLine::ForCurrentProcess()); 1342 1343 // Now the command line has been mutated based on about:flags, we can run some 1344 // field trials 1345 parts->SetupFieldTrials(); 1346 1347 // Now that all preferences have been registered, set the install date 1348 // for the uninstall metrics if this is our first run. This only actually 1349 // gets used if the user has metrics reporting enabled at uninstall time. 1350 int64 install_date = 1351 local_state->GetInt64(prefs::kUninstallMetricsInstallDate); 1352 if (install_date == 0) { 1353 local_state->SetInt64(prefs::kUninstallMetricsInstallDate, 1354 base::Time::Now().ToTimeT()); 1355 } 1356 1357 #if defined(OS_MACOSX) 1358 // Get the Keychain API to register for distributed notifications on the main 1359 // thread, which has a proper CFRunloop, instead of later on the I/O thread, 1360 // which doesn't. This ensures those notifications will get delivered 1361 // properly. See issue 37766. 1362 // (Note that the callback mask here is empty. I don't want to register for 1363 // any callbacks, I just want to initialize the mechanism.) 1364 SecKeychainAddCallback(&KeychainCallback, 0, NULL); 1365 #endif 1366 1367 CreateChildThreads(browser_process.get()); 1368 1369 #if defined(OS_CHROMEOS) 1370 // Now that the file thread exists we can record our stats. 1371 chromeos::BootTimesLoader::Get()->RecordChromeMainStats(); 1372 1373 // Read locale-specific GTK resource information. 1374 std::string gtkrc = l10n_util::GetStringUTF8(IDS_LOCALE_GTKRC); 1375 if (!gtkrc.empty()) 1376 gtk_rc_parse_string(gtkrc.c_str()); 1377 1378 // Trigger prefetching of ownership status. 1379 chromeos::OwnershipService::GetSharedInstance()->Prewarm(); 1380 #endif 1381 1382 // Record last shutdown time into a histogram. 1383 browser_shutdown::ReadLastShutdownInfo(); 1384 1385 #if defined(OS_WIN) 1386 // On Windows, we use our startup as an opportunity to do upgrade/uninstall 1387 // tasks. Those care whether the browser is already running. On Linux/Mac, 1388 // upgrade/uninstall happen separately. 1389 bool already_running = browser_util::IsBrowserAlreadyRunning(); 1390 1391 // If the command line specifies 'uninstall' then we need to work here 1392 // unless we detect another chrome browser running. 1393 if (parsed_command_line.HasSwitch(switches::kUninstall)) 1394 return DoUninstallTasks(already_running); 1395 #endif 1396 1397 if (parsed_command_line.HasSwitch(switches::kHideIcons) || 1398 parsed_command_line.HasSwitch(switches::kShowIcons)) 1399 return HandleIconsCommands(parsed_command_line); 1400 if (parsed_command_line.HasSwitch(switches::kMakeDefaultBrowser)) { 1401 return ShellIntegration::SetAsDefaultBrowser() ? 1402 ResultCodes::NORMAL_EXIT : ResultCodes::SHELL_INTEGRATION_FAILED; 1403 } 1404 1405 // If the command line specifies --pack-extension, attempt the pack extension 1406 // startup action and exit. 1407 if (parsed_command_line.HasSwitch(switches::kPackExtension)) { 1408 ExtensionsStartupUtil extension_startup_util; 1409 if (extension_startup_util.PackExtension(parsed_command_line)) { 1410 return ResultCodes::NORMAL_EXIT; 1411 } else { 1412 return ResultCodes::PACK_EXTENSION_ERROR; 1413 } 1414 } 1415 1416 #if !defined(OS_MACOSX) 1417 // In environments other than Mac OS X we support import of settings 1418 // from other browsers. In case this process is a short-lived "import" 1419 // process that another browser runs just to import the settings, we 1420 // don't want to be checking for another browser process, by design. 1421 if (!(parsed_command_line.HasSwitch(switches::kImport) || 1422 parsed_command_line.HasSwitch(switches::kImportFromFile))) { 1423 #endif 1424 // When another process is running, use that process instead of starting a 1425 // new one. NotifyOtherProcess will currently give the other process up to 1426 // 20 seconds to respond. Note that this needs to be done before we attempt 1427 // to read the profile. 1428 switch (process_singleton.NotifyOtherProcessOrCreate()) { 1429 case ProcessSingleton::PROCESS_NONE: 1430 // No process already running, fall through to starting a new one. 1431 break; 1432 1433 case ProcessSingleton::PROCESS_NOTIFIED: 1434 #if defined(OS_POSIX) && !defined(OS_MACOSX) 1435 printf("%s\n", base::SysWideToNativeMB(UTF16ToWide( 1436 l10n_util::GetStringUTF16(IDS_USED_EXISTING_BROWSER))).c_str()); 1437 #endif 1438 return ResultCodes::NORMAL_EXIT; 1439 1440 case ProcessSingleton::PROFILE_IN_USE: 1441 return ResultCodes::PROFILE_IN_USE; 1442 1443 case ProcessSingleton::LOCK_ERROR: 1444 LOG(ERROR) << "Failed to create a ProcessSingleton for your profile " 1445 "directory. This means that running multiple instances " 1446 "would start multiple browser processes rather than " 1447 "opening a new window in the existing process. Aborting " 1448 "now to avoid profile corruption."; 1449 return ResultCodes::PROFILE_IN_USE; 1450 1451 default: 1452 NOTREACHED(); 1453 } 1454 #if !defined(OS_MACOSX) // closing brace for if 1455 } 1456 #endif 1457 1458 #if defined(USE_X11) 1459 SetBrowserX11ErrorHandlers(); 1460 #endif 1461 1462 // Override the default ContentBrowserClient to let Chrome participate in 1463 // content logic. Must be done before any tabs or profiles are created. 1464 chrome::ChromeContentBrowserClient browser_client; 1465 content::GetContentClient()->set_browser(&browser_client); 1466 1467 // Profile creation ---------------------------------------------------------- 1468 1469 #if defined(OS_CHROMEOS) 1470 // Stub out chromeos implementations. 1471 if (parsed_command_line.HasSwitch(switches::kStubCros)) 1472 chromeos::CrosLibrary::Get()->GetTestApi()->SetUseStubImpl(); 1473 1474 // Initialize the screen locker now so that it can receive 1475 // LOGIN_USER_CHANGED notification from UserManager. 1476 chromeos::ScreenLocker::InitClass(); 1477 1478 // This forces the ProfileManager to be created and register for the 1479 // notification it needs to track the logged in user. 1480 g_browser_process->profile_manager(); 1481 1482 // Allow access to file:// on ChromeOS for tests. 1483 if (parsed_command_line.HasSwitch(switches::kAllowFileAccess)) { 1484 net::URLRequest::AllowFileAccess(); 1485 } 1486 1487 // There are two use cases for kLoginUser: 1488 // 1) if passed in tandem with kLoginPassword, to drive a "StubLogin" 1489 // 2) if passed alone, to signal that the indicated user has already 1490 // logged in and we should behave accordingly. 1491 // This handles case 2. 1492 if (parsed_command_line.HasSwitch(switches::kLoginUser) && 1493 !parsed_command_line.HasSwitch(switches::kLoginPassword)) { 1494 std::string username = 1495 parsed_command_line.GetSwitchValueASCII(switches::kLoginUser); 1496 VLOG(1) << "Relaunching browser for user: " << username; 1497 chromeos::UserManager::Get()->UserLoggedIn(username); 1498 1499 // Redirects Chrome logging to the user data dir. 1500 logging::RedirectChromeLogging(parsed_command_line); 1501 } 1502 #endif 1503 1504 Profile* profile = CreateProfile(parameters, user_data_dir); 1505 if (!profile) 1506 return ResultCodes::NORMAL_EXIT; 1507 1508 // Post-profile init --------------------------------------------------------- 1509 1510 PrefService* user_prefs = profile->GetPrefs(); 1511 DCHECK(user_prefs); 1512 1513 // Tests should be able to tune login manager before showing it. 1514 // Thus only show login manager in normal (non-testing) mode. 1515 if (!parameters.ui_task) { 1516 OptionallyRunChromeOSLoginManager(parsed_command_line); 1517 } 1518 1519 #if !defined(OS_MACOSX) 1520 // Importing other browser settings is done in a browser-like process 1521 // that exits when this task has finished. 1522 // TODO(port): Port the Mac's IPC-based implementation to other platforms to 1523 // replace this implementation. http://crbug.com/22142 1524 if (parsed_command_line.HasSwitch(switches::kImport) || 1525 parsed_command_line.HasSwitch(switches::kImportFromFile)) { 1526 return FirstRun::ImportNow(profile, parsed_command_line); 1527 } 1528 #endif 1529 1530 #if defined(OS_WIN) 1531 // Do the tasks if chrome has been upgraded while it was last running. 1532 if (!already_running && upgrade_util::DoUpgradeTasks(parsed_command_line)) 1533 return ResultCodes::NORMAL_EXIT; 1534 #endif 1535 1536 // Check if there is any machine level Chrome installed on the current 1537 // machine. If yes and the current Chrome process is user level, we do not 1538 // allow the user level Chrome to run. So we notify the user and uninstall 1539 // user level Chrome. 1540 // Note this check should only happen here, after all the checks above 1541 // (uninstall, resource bundle initialization, other chrome browser 1542 // processes etc). 1543 if (CheckMachineLevelInstall()) 1544 return ResultCodes::MACHINE_LEVEL_INSTALL_EXISTS; 1545 1546 // Create the TranslateManager singleton. 1547 TranslateManager::GetInstance(); 1548 1549 #if defined(OS_MACOSX) 1550 if (!parsed_command_line.HasSwitch(switches::kNoFirstRun)) { 1551 // Disk image installation is sort of a first-run task, so it shares the 1552 // kNoFirstRun switch. 1553 if (MaybeInstallFromDiskImage()) { 1554 // The application was installed and the installed copy has been 1555 // launched. This process is now obsolete. Exit. 1556 return ResultCodes::NORMAL_EXIT; 1557 } 1558 } 1559 #endif 1560 1561 // Show the First Run UI if this is the first time Chrome has been run on 1562 // this computer, or we're being compelled to do so by a command line flag. 1563 // Note that this be done _after_ the PrefService is initialized and all 1564 // preferences are registered, since some of the code that the importer 1565 // touches reads preferences. 1566 if (is_first_run) { 1567 if (!first_run_ui_bypass) { 1568 FirstRun::AutoImport(profile, 1569 master_prefs.homepage_defined, 1570 master_prefs.do_import_items, 1571 master_prefs.dont_import_items, 1572 master_prefs.run_search_engine_experiment, 1573 master_prefs.randomize_search_engine_experiment, 1574 master_prefs.make_chrome_default, 1575 &process_singleton); 1576 #if defined(OS_POSIX) 1577 // On Windows, the download is tagged with enable/disable stats so there 1578 // is no need for this code. 1579 1580 // If stats reporting was turned on by the first run dialog then toggle 1581 // the pref. 1582 if (GoogleUpdateSettings::GetCollectStatsConsent()) 1583 local_state->SetBoolean(prefs::kMetricsReportingEnabled, true); 1584 #endif // OS_POSIX 1585 } // if (!first_run_ui_bypass) 1586 1587 Browser::SetNewHomePagePrefs(user_prefs); 1588 } 1589 1590 // Sets things up so that if we crash from this point on, a dialog will 1591 // popup asking the user to restart chrome. It is done this late to avoid 1592 // testing against a bunch of special cases that are taken care early on. 1593 PrepareRestartOnCrashEnviroment(parsed_command_line); 1594 1595 #if defined(OS_WIN) 1596 // Registers Chrome with the Windows Restart Manager, which will restore the 1597 // Chrome session when the computer is restarted after a system update. 1598 // This could be run as late as WM_QUERYENDSESSION for system update reboots, 1599 // but should run on startup if extended to handle crashes/hangs/patches. 1600 // Also, better to run once here than once for each HWND's WM_QUERYENDSESSION. 1601 if (base::win::GetVersion() >= base::win::VERSION_VISTA) { 1602 bool result = RegisterApplicationRestart(parsed_command_line); 1603 DCHECK(result); 1604 } 1605 #endif // OS_WIN 1606 1607 // Initialize and maintain network predictor module, which handles DNS 1608 // pre-resolution, as well as TCP/IP connection pre-warming. 1609 // This also registers an observer to discard data when closing incognito 1610 // mode. 1611 bool preconnect_enabled = true; // Default status (easy to change!). 1612 if (parsed_command_line.HasSwitch(switches::kDisablePreconnect)) 1613 preconnect_enabled = false; 1614 else if (parsed_command_line.HasSwitch(switches::kEnablePreconnect)) 1615 preconnect_enabled = true; 1616 chrome_browser_net::PredictorInit dns_prefetch( 1617 user_prefs, 1618 local_state, 1619 preconnect_enabled); 1620 1621 #if defined(OS_WIN) 1622 app::win::ScopedCOMInitializer com_initializer; 1623 1624 #if defined(GOOGLE_CHROME_BUILD) 1625 // Init the RLZ library. This just binds the dll and schedules a task on the 1626 // file thread to be run sometime later. If this is the first run we record 1627 // the installation event. 1628 RLZTracker::InitRlzDelayed(is_first_run, master_prefs.ping_delay); 1629 #endif // GOOGLE_CHROME_BUILD 1630 #endif // OS_WIN 1631 1632 // Configure modules that need access to resources. 1633 net::NetModule::SetResourceProvider(chrome_common_net::NetResourceProvider); 1634 1635 // Register our global network handler for chrome:// and 1636 // chrome-extension:// URLs. 1637 ChromeURLDataManagerBackend::Register(); 1638 RegisterExtensionProtocols(); 1639 RegisterMetadataURLRequestHandler(); 1640 RegisterBlobURLRequestJobFactory(); 1641 RegisterFileSystemURLRequestJobFactory(); 1642 1643 // In unittest mode, this will do nothing. In normal mode, this will create 1644 // the global GoogleURLTracker and IntranetRedirectDetector instances, which 1645 // will promptly go to sleep for five and seven seconds, respectively (to 1646 // avoid slowing startup), and wake up afterwards to see if they should do 1647 // anything else. 1648 // 1649 // A simpler way of doing all this would be to have some function which could 1650 // give the time elapsed since startup, and simply have these objects check 1651 // that when asked to initialize themselves, but this doesn't seem to exist. 1652 // 1653 // These can't be created in the BrowserProcessImpl constructor because they 1654 // need to read prefs that get set after that runs. 1655 browser_process->google_url_tracker(); 1656 browser_process->intranet_redirect_detector(); 1657 1658 // Do initialize the plug-in service (and related preferences). 1659 PluginService::InitGlobalInstance(profile); 1660 1661 // Prepare for memory caching of SDCH dictionaries. 1662 // Perform A/B test to measure global impact of SDCH support. 1663 // Set up a field trial to see what disabling SDCH does to latency of page 1664 // layout globally. 1665 base::FieldTrial::Probability kSDCH_DIVISOR = 1000; 1666 base::FieldTrial::Probability kSDCH_DISABLE_PROBABILITY = 1; // 0.1% prob. 1667 // After June 30, 2011 builds, it will always be in default group. 1668 scoped_refptr<base::FieldTrial> sdch_trial( 1669 new base::FieldTrial("GlobalSdch", kSDCH_DIVISOR, "global_enable_sdch", 1670 2011, 6, 30)); 1671 int sdch_enabled = sdch_trial->kDefaultGroupNumber; 1672 1673 // Use default of "" so that all domains are supported. 1674 std::string sdch_supported_domain(""); 1675 if (parsed_command_line.HasSwitch(switches::kSdchFilter)) { 1676 sdch_supported_domain = 1677 parsed_command_line.GetSwitchValueASCII(switches::kSdchFilter); 1678 } else { 1679 sdch_trial->AppendGroup("global_disable_sdch", 1680 kSDCH_DISABLE_PROBABILITY); 1681 if (sdch_enabled != sdch_trial->group()) 1682 sdch_supported_domain = "never_enabled_sdch_for_any_domain"; 1683 } 1684 1685 net::SdchManager sdch_manager; // Singleton database. 1686 sdch_manager.set_sdch_fetcher(new SdchDictionaryFetcher); 1687 sdch_manager.EnableSdchSupport(sdch_supported_domain); 1688 1689 MetricsService* metrics = InitializeMetrics(parsed_command_line, local_state); 1690 InstallJankometer(parsed_command_line); 1691 1692 #if defined(OS_WIN) && !defined(GOOGLE_CHROME_BUILD) 1693 if (parsed_command_line.HasSwitch(switches::kDebugPrint)) { 1694 FilePath path = 1695 parsed_command_line.GetSwitchValuePath(switches::kDebugPrint); 1696 printing::PrintedDocument::set_debug_dump_path(path); 1697 } 1698 #endif 1699 1700 #if defined(TOUCH_UI) 1701 views::RootView::SetKeepMouseCursor( 1702 CommandLine::ForCurrentProcess()->HasSwitch(switches::kKeepMouseCursor)); 1703 #endif 1704 1705 HandleTestParameters(parsed_command_line); 1706 RecordBreakpadStatusUMA(metrics); 1707 about_flags::RecordUMAStatistics(local_state); 1708 1709 #if defined(OS_CHROMEOS) 1710 metrics->StartExternalMetrics(); 1711 1712 // Initialize the brightness observer so that we'll display an onscreen 1713 // indication of brightness changes during login. 1714 static chromeos::BrightnessObserver* brightness_observer = 1715 new chromeos::BrightnessObserver(); 1716 chromeos::CrosLibrary::Get()->GetBrightnessLibrary()->AddObserver( 1717 brightness_observer); 1718 1719 // Listen for system key events so that the user will be able to adjust the 1720 // volume on the login screen. 1721 chromeos::SystemKeyEventListener::GetInstance(); 1722 #endif 1723 1724 // Initialize extension event routers. Note that on Chrome OS, this will 1725 // not succeed if the user has not logged in yet, in which case the 1726 // event routers are initialized in LoginUtilsImpl::CompleteLogin instead. 1727 if (profile->GetExtensionService()) { 1728 // This will initialize bookmarks. Call it after bookmark import is done. 1729 // See issue 40144. 1730 profile->GetExtensionService()->InitEventRouters(); 1731 } 1732 1733 // The extension service may be available at this point. If the command line 1734 // specifies --uninstall-extension, attempt the uninstall extension startup 1735 // action. 1736 if (parsed_command_line.HasSwitch(switches::kUninstallExtension)) { 1737 ExtensionsStartupUtil ext_startup_util; 1738 if (ext_startup_util.UninstallExtension(parsed_command_line, profile)) { 1739 return ResultCodes::NORMAL_EXIT; 1740 } else { 1741 return ResultCodes::UNINSTALL_EXTENSION_ERROR; 1742 } 1743 } 1744 1745 #if defined(OS_WIN) 1746 // We check this here because if the profile is OTR (chromeos possibility) 1747 // it won't still be accessible after browser is destroyed. 1748 bool record_search_engine = is_first_run && !profile->IsOffTheRecord(); 1749 #endif 1750 1751 // ChildProcess:: is a misnomer unless you consider context. Use 1752 // of --wait-for-debugger only makes sense when Chrome itself is a 1753 // child process (e.g. when launched by PyAuto). 1754 if (parsed_command_line.HasSwitch(switches::kWaitForDebugger)) { 1755 ChildProcess::WaitForDebugger("Browser"); 1756 } 1757 1758 // If remoting or cloud print proxy is enabled and setup has been completed 1759 // we start the service process here. 1760 // The prerequisite for running the service process is that we have IO, UI 1761 // and PROCESS_LAUNCHER threads up and running. 1762 // TODO(hclam): Need to check for cloud print proxy too. 1763 if (parsed_command_line.HasSwitch(switches::kEnableRemoting)) { 1764 if (user_prefs->GetBoolean(prefs::kRemotingHasSetupCompleted)) { 1765 ServiceProcessControl* control = 1766 ServiceProcessControlManager::GetInstance()->GetProcessControl( 1767 profile); 1768 control->Launch(NULL, NULL); 1769 } 1770 } 1771 1772 #if defined(OS_CHROMEOS) 1773 // Run the Out of Memory priority manager while in this scope. Wait 1774 // until here to start so that we give the most amount of time for 1775 // the other services to start up before we start adjusting the oom 1776 // priority. In reality, it doesn't matter much where in this scope 1777 // this is started, but it must be started in this scope so it will 1778 // also be terminated when this scope exits. 1779 scoped_ptr<browser::OomPriorityManager> oom_priority_manager( 1780 new browser::OomPriorityManager); 1781 #endif 1782 1783 // Create the instance of the cloud print proxy service so that it can launch 1784 // the service process if needed. This is needed because the service process 1785 // might have shutdown because an update was available. 1786 profile->GetCloudPrintProxyService(); 1787 1788 // Schedule a GPU blacklist auto update. This also loads the current one. 1789 scoped_refptr<GpuBlacklistUpdater> gpu_blacklist_updater = 1790 new GpuBlacklistUpdater(); 1791 // Don't start auto update in tests. 1792 if (parsed_command_line.GetSwitchValueASCII(switches::kUseGL) != 1793 gfx::kGLImplementationOSMesaName) { 1794 gpu_blacklist_updater->StartAfterDelay(); 1795 } 1796 1797 // Start watching all browser threads for responsiveness. 1798 ThreadWatcherList::StartWatchingAll(); 1799 1800 int result_code = ResultCodes::NORMAL_EXIT; 1801 if (parameters.ui_task) { 1802 // We are in test mode. Run one task and enter the main message loop. 1803 if (pool) 1804 pool->Recycle(); 1805 parameters.ui_task->Run(); 1806 delete parameters.ui_task; 1807 } else { 1808 // Most general initialization is behind us, but opening a 1809 // tab and/or session restore and such is still to be done. 1810 base::TimeTicks browser_open_start = base::TimeTicks::Now(); 1811 1812 // We are in regular browser boot sequence. Open initial tabs and enter the 1813 // main message loop. 1814 if (browser_init.Start(parsed_command_line, FilePath(), profile, 1815 &result_code)) { 1816 #if (defined(OS_WIN) || defined(OS_LINUX)) && !defined(OS_CHROMEOS) 1817 // Initialize autoupdate timer. Timer callback costs basically nothing 1818 // when browser is not in persistent mode, so it's OK to let it ride on 1819 // the main thread. This needs to be done here because we don't want 1820 // to start the timer when Chrome is run inside a test harness. 1821 g_browser_process->StartAutoupdateTimer(); 1822 #endif 1823 1824 #if defined(OS_LINUX) && !defined(OS_CHROMEOS) 1825 // On Linux, the running exe will be updated if an upgrade becomes 1826 // available while the browser is running. We need to save the last 1827 // modified time of the exe, so we can compare to determine if there is 1828 // an upgrade while the browser is kept alive by a persistent extension. 1829 upgrade_util::SaveLastModifiedTimeOfExe(); 1830 #endif 1831 1832 // Record now as the last successful chrome start. 1833 GoogleUpdateSettings::SetLastRunTime(); 1834 // Call Recycle() here as late as possible, before going into the loop 1835 // because Start() will add things to it while creating the main window. 1836 if (pool) 1837 pool->Recycle(); 1838 1839 UMA_HISTOGRAM_MEDIUM_TIMES("Startup.BrowserOpenTabs", 1840 base::TimeTicks::Now() - browser_open_start); 1841 1842 RunUIMessageLoop(browser_process.get()); 1843 } 1844 } 1845 1846 #if defined(OS_WIN) 1847 // If it's the first run, log the search engine chosen. We wait until 1848 // shutdown because otherwise we can't be sure the user has finished 1849 // selecting a search engine through the dialog reached from the first run 1850 // bubble link. 1851 if (record_search_engine) { 1852 const TemplateURL* default_search_engine = 1853 profile->GetTemplateURLModel()->GetDefaultSearchProvider(); 1854 // The default engine can be NULL if the administrator has disabled 1855 // default search. 1856 SearchEngineType search_engine_type = 1857 default_search_engine ? default_search_engine->search_engine_type() : 1858 SEARCH_ENGINE_OTHER; 1859 // Record the search engine chosen. 1860 if (master_prefs.run_search_engine_experiment) { 1861 UMA_HISTOGRAM_ENUMERATION( 1862 "Chrome.SearchSelectExperiment", 1863 search_engine_type, 1864 SEARCH_ENGINE_MAX); 1865 // If the selection has been randomized, also record the winner by slot. 1866 if (master_prefs.randomize_search_engine_experiment) { 1867 size_t engine_pos = profile->GetTemplateURLModel()-> 1868 GetSearchEngineDialogSlot(); 1869 if (engine_pos < 4) { 1870 std::string experiment_type = "Chrome.SearchSelectExperimentSlot"; 1871 // Nicer in UMA if slots are 1-based. 1872 experiment_type.push_back('1' + engine_pos); 1873 UMA_HISTOGRAM_ENUMERATION( 1874 experiment_type, 1875 search_engine_type, 1876 SEARCH_ENGINE_MAX); 1877 } else { 1878 NOTREACHED() << "Invalid search engine selection slot."; 1879 } 1880 } 1881 } else { 1882 UMA_HISTOGRAM_ENUMERATION( 1883 "Chrome.SearchSelectExempt", 1884 search_engine_type, 1885 SEARCH_ENGINE_MAX); 1886 } 1887 } 1888 #endif 1889 1890 chrome_browser_net_websocket_experiment::WebSocketExperimentRunner::Stop(); 1891 1892 process_singleton.Cleanup(); 1893 1894 // Stop all tasks that might run on WatchDogThread. 1895 ThreadWatcherList::StopWatchingAll(); 1896 1897 metrics->Stop(); 1898 1899 // browser_shutdown takes care of deleting browser_process, so we need to 1900 // release it. 1901 ignore_result(browser_process.release()); 1902 browser_shutdown::Shutdown(); 1903 1904 #if defined(OS_CHROMEOS) 1905 // To be precise, logout (browser shutdown) is not yet done, but the 1906 // remaining work is negligible, hence we say LogoutDone here. 1907 chromeos::BootTimesLoader::Get()->AddLogoutTimeMarker("LogoutDone", 1908 false); 1909 chromeos::BootTimesLoader::Get()->WriteLogoutTimes(); 1910 #endif 1911 TRACE_EVENT_END("BrowserMain", 0, 0); 1912 return result_code; 1913 } 1914