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
BrowserMainParts(const MainFunctionParams & parameters)210 BrowserMainParts::BrowserMainParts(const MainFunctionParams& parameters)
211 : parameters_(parameters),
212 parsed_command_line_(parameters.command_line_) {
213 }
214
~BrowserMainParts()215 BrowserMainParts::~BrowserMainParts() {
216 }
217
218 // BrowserMainParts: |EarlyInitialization()| and related -----------------------
219
EarlyInitialization()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
SetupFieldTrials()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.
ConnectionFieldTrial()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.
SocketTimeoutFieldTrial()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
ProxyConnectionsFieldTrial()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.
SpdyFieldTrial()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
SSLFalseStartFieldTrial()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.
ConnectBackupJobsFieldTrial()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
MainMessageLoopStart()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
InitializeMainThread()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.
HandleTestParameters(const CommandLine & command_line)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
RunUIMessageLoop(BrowserProcess * browser_process)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
AddFirstRunNewTabs(BrowserInit * browser_init,const std::vector<GURL> & new_tabs)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:
GetLinuxDistroTask()613 explicit GetLinuxDistroTask() {}
614
Run()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
InitializeNetworkOptions(const CommandLine & parsed_command_line)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.
CreateChildThreads(BrowserProcessImpl * process)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.
InitializeLocalState(const CommandLine & parsed_command_line,bool is_first_run)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.
InitializeBrokerServices(const MainFunctionParams & parameters,const CommandLine & parsed_command_line)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).
InitializeMetrics(const CommandLine & parsed_command_line,const PrefService * local_state)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.
CreateProfile(const MainFunctionParams & parameters,const FilePath & user_data_dir)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
AdjustUIFont(LOGFONT * logfont)860 void AdjustUIFont(LOGFONT* logfont) {
861 l10n_util::AdjustUIFont(logfont);
862 }
863
GetMinimumFontSize()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)
GLibLogHandler(const gchar * log_domain,GLogLevelFlags log_level,const gchar * message,gpointer userdata)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
SetUpGLibLogHandler()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
InitializeToolkit(const MainFunctionParams & parameters)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:
StubLogin(std::string username,std::string password)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
OnLoginFailure(const chromeos::LoginFailure & error)1007 void OnLoginFailure(const chromeos::LoginFailure& error) {
1008 LOG(ERROR) << "Login Failure: " << error.GetErrorString();
1009 delete this;
1010 }
1011
OnLoginSuccess(const std::string & username,const std::string & password,const GaiaAuthConsumer::ClientLoginResult & credentials,bool pending_requests)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:
OnProfilePrepared(Profile * profile)1025 virtual void OnProfilePrepared(Profile* profile) {
1026 chromeos::LoginUtils::DoBrowserLaunch(profile);
1027 delete this;
1028 }
1029
1030 scoped_refptr<chromeos::Authenticator> authenticator_;
1031 };
1032
OptionallyRunChromeOSLoginManager(const CommandLine & parsed_command_line)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
OptionallyRunChromeOSLoginManager(const CommandLine & parsed_command_line)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)
KeychainCallback(SecKeychainEvent keychain_event,SecKeychainCallbackInfo * info,void * context)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
RelaunchChromeBrowserWithNewCommandLineIfNeeded()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)
IsMetricsReportingEnabled(const PrefService * local_state)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.
BrowserMain(const MainFunctionParams & parameters)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