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
210BrowserMainParts::BrowserMainParts(const MainFunctionParams& parameters)
211    : parameters_(parameters),
212      parsed_command_line_(parameters.command_line_) {
213}
214
215BrowserMainParts::~BrowserMainParts() {
216}
217
218// BrowserMainParts: |EarlyInitialization()| and related -----------------------
219
220void 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
247void 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.
265void 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.
311void 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
347void 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.
393void 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
459void 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.
485void 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
513void 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
536void 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
549namespace {
550
551// This function provides some ways to test crash and assertion handling
552// behavior of the program.
553void 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
574void 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
601void 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)
611class GetLinuxDistroTask : public Task {
612 public:
613  explicit GetLinuxDistroTask() {}
614
615  virtual void Run() {
616    base::GetLinuxDistro();  // Initialize base::linux_distro if needed.
617  }
618
619  DISALLOW_COPY_AND_ASSIGN(GetLinuxDistroTask);
620};
621#endif  // USE_LINUX_BREAKPAD
622
623void 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.
660void 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.
672PrefService* 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.
754void 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).
776MetricsService* 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.
816Profile* 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
860void AdjustUIFont(LOGFONT* logfont) {
861  l10n_util::AdjustUIFont(logfont);
862}
863
864int 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)
874static 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
914static 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
930void 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.
994class StubLogin : public chromeos::LoginStatusConsumer,
995                  public chromeos::LoginUtils::Delegate {
996 public:
997  explicit StubLogin(std::string username, std::string password) {
998    authenticator_ = chromeos::LoginUtils::Get()->CreateAuthenticator(this);
999    authenticator_.get()->AuthenticateToLogin(
1000        g_browser_process->profile_manager()->GetDefaultProfile(),
1001        username,
1002        password,
1003        std::string(),
1004        std::string());
1005  }
1006
1007  void OnLoginFailure(const chromeos::LoginFailure& error) {
1008    LOG(ERROR) << "Login Failure: " << error.GetErrorString();
1009    delete this;
1010  }
1011
1012  void OnLoginSuccess(const std::string& username,
1013                      const std::string& password,
1014                      const GaiaAuthConsumer::ClientLoginResult& credentials,
1015                      bool pending_requests) {
1016    // Will call OnProfilePrepared in the end.
1017    chromeos::LoginUtils::Get()->PrepareProfile(username,
1018                                                password,
1019                                                credentials,
1020                                                pending_requests,
1021                                                this);
1022  }
1023
1024  // LoginUtils::Delegate implementation:
1025  virtual void OnProfilePrepared(Profile* profile) {
1026    chromeos::LoginUtils::DoBrowserLaunch(profile);
1027    delete this;
1028  }
1029
1030  scoped_refptr<chromeos::Authenticator> authenticator_;
1031};
1032
1033void 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
1065void 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)
1072OSStatus 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.
1083DISABLE_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.
1090extern "C" {
1091DLLEXPORT void __cdecl RelaunchChromeBrowserWithNewCommandLineIfNeeded();
1092}
1093
1094DLLEXPORT 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)
1104bool 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.
1129int 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