• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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