chromeos: bluetooth: tie Proxy lifetime to object, not observer
[chromium-blink-merge.git] / chrome / browser / chrome_browser_main.cc
blobdf2462969fd9057683f1b3413593c5395fc6eb57
1 // Copyright (c) 2012 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.
5 #include "chrome/browser/chrome_browser_main.h"
7 #include <algorithm>
8 #include <string>
9 #include <vector>
11 #include "base/at_exit.h"
12 #include "base/bind.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/metrics/field_trial.h"
18 #include "base/metrics/histogram.h"
19 #include "base/path_service.h"
20 #include "base/process_util.h"
21 #include "base/string_number_conversions.h"
22 #include "base/string_piece.h"
23 #include "base/string_split.h"
24 #include "base/string_util.h"
25 #include "base/sys_string_conversions.h"
26 #include "base/threading/platform_thread.h"
27 #include "base/time.h"
28 #include "base/utf_string_conversions.h"
29 #include "base/values.h"
30 #include "build/build_config.h"
31 #include "chrome/browser/about_flags.h"
32 #include "chrome/browser/auto_launch_trial.h"
33 #include "chrome/browser/autocomplete/autocomplete_field_trial.h"
34 #include "chrome/browser/background/background_mode_manager.h"
35 #include "chrome/browser/browser_process_impl.h"
36 #include "chrome/browser/browser_shutdown.h"
37 #include "chrome/browser/chrome_browser_main_extra_parts.h"
38 #include "chrome/browser/defaults.h"
39 #include "chrome/browser/extensions/default_apps_trial.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_browser_process.h"
44 #include "chrome/browser/first_run/upgrade_util.h"
45 #include "chrome/browser/google/google_url_tracker.h"
46 #include "chrome/browser/google/google_util.h"
47 #include "chrome/browser/instant/instant_field_trial.h"
48 #include "chrome/browser/jankometer.h"
49 #include "chrome/browser/language_usage_metrics.h"
50 #include "chrome/browser/metrics/field_trial_synchronizer.h"
51 #include "chrome/browser/metrics/histogram_synchronizer.h"
52 #include "chrome/browser/metrics/metrics_log.h"
53 #include "chrome/browser/metrics/metrics_service.h"
54 #include "chrome/browser/metrics/thread_watcher.h"
55 #include "chrome/browser/metrics/tracking_synchronizer.h"
56 #include "chrome/browser/nacl_host/nacl_process_host.h"
57 #include "chrome/browser/net/chrome_net_log.h"
58 #include "chrome/browser/net/predictor.h"
59 #include "chrome/browser/notifications/desktop_notification_service_factory.h"
60 #include "chrome/browser/notifications/desktop_notification_service.h"
61 #include "chrome/browser/plugin_prefs.h"
62 #include "chrome/browser/prefs/pref_service.h"
63 #include "chrome/browser/prefs/pref_value_store.h"
64 #include "chrome/browser/prefs/scoped_user_pref_update.h"
65 #include "chrome/browser/prerender/prerender_field_trial.h"
66 #include "chrome/browser/printing/cloud_print/cloud_print_proxy_service_factory.h"
67 #include "chrome/browser/printing/cloud_print/cloud_print_proxy_service.h"
68 #include "chrome/browser/process_singleton.h"
69 #include "chrome/browser/profiles/profile.h"
70 #include "chrome/browser/profiles/profile_manager.h"
71 #include "chrome/browser/search_engines/search_engine_type.h"
72 #include "chrome/browser/search_engines/template_url.h"
73 #include "chrome/browser/search_engines/template_url_service_factory.h"
74 #include "chrome/browser/search_engines/template_url_service.h"
75 #include "chrome/browser/service/service_process_control.h"
76 #include "chrome/browser/shell_integration.h"
77 #include "chrome/browser/translate/translate_manager.h"
78 #include "chrome/browser/ui/browser.h"
79 #include "chrome/browser/ui/browser_init.h"
80 #include "chrome/browser/ui/webui/chrome_url_data_manager_backend.h"
81 #include "chrome/browser/ui/webui/ntp/new_tab_ui.h"
82 #include "chrome/browser/ui/webui/sync_promo/sync_promo_trial.h"
83 #include "chrome/common/child_process_logging.h"
84 #include "chrome/common/chrome_constants.h"
85 #include "chrome/common/chrome_paths.h"
86 #include "chrome/common/chrome_result_codes.h"
87 #include "chrome/common/chrome_switches.h"
88 #include "chrome/common/chrome_version_info.h"
89 #include "chrome/common/env_vars.h"
90 #include "chrome/common/json_pref_store.h"
91 #include "chrome/common/jstemplate_builder.h"
92 #include "chrome/common/logging_chrome.h"
93 #include "chrome/common/net/net_resource_provider.h"
94 #include "chrome/common/pref_names.h"
95 #include "chrome/common/profiling.h"
96 #include "chrome/installer/util/google_update_settings.h"
97 #include "content/browser/gpu/gpu_blacklist.h"
98 #include "content/browser/gpu/gpu_data_manager.h"
99 #include "content/public/browser/browser_thread.h"
100 #include "content/public/common/content_client.h"
101 #include "content/public/common/main_function_params.h"
102 #include "grit/app_locale_settings.h"
103 #include "grit/browser_resources.h"
104 #include "grit/chromium_strings.h"
105 #include "grit/generated_resources.h"
106 #include "grit/platform_locale_settings.h"
107 #include "net/base/cookie_monster.h"
108 #include "net/base/net_module.h"
109 #include "net/base/sdch_manager.h"
110 #include "net/http/http_basic_stream.h"
111 #include "net/http/http_network_layer.h"
112 #include "net/http/http_stream_factory.h"
113 #include "net/socket/client_socket_pool_base.h"
114 #include "net/socket/client_socket_pool_manager.h"
115 #include "net/spdy/spdy_session.h"
116 #include "net/spdy/spdy_session_pool.h"
117 #include "net/url_request/url_request.h"
118 #include "net/url_request/url_request_throttler_manager.h"
119 #include "net/websockets/websocket_job.h"
120 #include "ui/base/l10n/l10n_util.h"
121 #include "ui/base/resource/resource_bundle.h"
123 #if defined(USE_LINUX_BREAKPAD)
124 #include "base/linux_util.h"
125 #include "chrome/app/breakpad_linux.h"
126 #endif
128 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
129 #include "chrome/browser/first_run/upgrade_util_linux.h"
130 #endif
132 #if defined(OS_CHROMEOS)
133 #include "chrome/browser/chromeos/cros/cros_library.h"
134 #include "chrome/browser/chromeos/cros_settings.h"
135 #include "chrome/browser/chromeos/cros_settings_names.h"
136 #endif
138 // TODO(port): several win-only methods have been pulled out of this, but
139 // BrowserMain() as a whole needs to be broken apart so that it's usable by
140 // other platforms. For now, it's just a stub. This is a serious work in
141 // progress and should not be taken as an indication of a real refactoring.
143 #if defined(OS_WIN)
144 #include "base/environment.h" // For PreRead experiment.
145 #include "base/win/windows_version.h"
146 #include "chrome/browser/browser_trial.h"
147 #include "chrome/browser/browser_util_win.h"
148 #include "chrome/browser/chrome_browser_main_win.h"
149 #include "chrome/browser/first_run/try_chrome_dialog_view.h"
150 #include "chrome/browser/first_run/upgrade_util_win.h"
151 #include "chrome/browser/net/url_fixer_upper.h"
152 #include "chrome/browser/rlz/rlz.h"
153 #include "chrome/browser/ui/views/user_data_dir_dialog.h"
154 #include "chrome/installer/util/helper.h"
155 #include "chrome/installer/util/install_util.h"
156 #include "chrome/installer/util/shell_util.h"
157 #include "net/base/net_util.h"
158 #include "printing/printed_document.h"
159 #include "ui/base/l10n/l10n_util_win.h"
160 #endif // defined(OS_WIN)
162 #if defined(OS_MACOSX)
163 #include <Security/Security.h>
165 #include "base/mac/scoped_nsautorelease_pool.h"
166 #include "chrome/browser/mac/install_from_dmg.h"
167 #include "chrome/browser/mac/keystone_glue.h"
168 #endif
170 #if defined(TOOLKIT_VIEWS)
171 #include "ui/views/focus/accelerator_handler.h"
172 #endif
174 #if defined(TOOLKIT_USES_GTK)
175 #include "chrome/browser/ui/gtk/gtk_util.h"
176 #include "ui/gfx/gtk_util.h"
177 #endif
179 #if defined(USE_X11)
180 #include "chrome/browser/chrome_browser_main_x11.h"
181 #endif
183 #if defined(USE_AURA)
184 #include "ui/aura/root_window.h"
185 #endif
187 using content::BrowserThread;
189 namespace net {
190 class NetLog;
191 } // namespace net
193 namespace {
195 // This function provides some ways to test crash and assertion handling
196 // behavior of the program.
197 void HandleTestParameters(const CommandLine& command_line) {
198 // This parameter causes an assertion.
199 if (command_line.HasSwitch(switches::kBrowserAssertTest)) {
200 DCHECK(false);
203 // This parameter causes a null pointer crash (crash reporter trigger).
204 if (command_line.HasSwitch(switches::kBrowserCrashTest)) {
205 int* bad_pointer = NULL;
206 *bad_pointer = 0;
209 #if defined(OS_CHROMEOS)
210 // Test loading libcros and exit. We return 0 if the library could be loaded,
211 // and 1 if it can't be. This is for validation that the library is installed
212 // and versioned properly for Chrome to find.
213 if (command_line.HasSwitch(switches::kTestLoadLibcros))
214 exit(!chromeos::CrosLibrary::Get()->libcros_loaded());
215 #endif
218 void AddFirstRunNewTabs(BrowserInit* browser_init,
219 const std::vector<GURL>& new_tabs) {
220 for (std::vector<GURL>::const_iterator it = new_tabs.begin();
221 it != new_tabs.end(); ++it) {
222 if (it->is_valid())
223 browser_init->AddFirstRunTab(*it);
227 #if defined(USE_LINUX_BREAKPAD)
228 void GetLinuxDistroCallback() {
229 base::GetLinuxDistro(); // Initialize base::linux_distro if needed.
231 #endif // USE_LINUX_BREAKPAD
233 void InitializeNetworkOptions(const CommandLine& parsed_command_line) {
234 if (parsed_command_line.HasSwitch(switches::kEnableFileCookies)) {
235 // Enable cookie storage for file:// URLs. Must do this before the first
236 // Profile (and therefore the first CookieMonster) is created.
237 net::CookieMonster::EnableFileScheme();
240 if (parsed_command_line.HasSwitch(switches::kEnableMacCookies))
241 net::URLRequest::EnableMacCookies();
243 if (parsed_command_line.HasSwitch(switches::kIgnoreCertificateErrors))
244 net::HttpStreamFactory::set_ignore_certificate_errors(true);
246 if (parsed_command_line.HasSwitch(switches::kHostRules))
247 net::HttpStreamFactory::SetHostMappingRules(
248 parsed_command_line.GetSwitchValueASCII(switches::kHostRules));
250 if (parsed_command_line.HasSwitch(switches::kEnableIPPooling))
251 net::SpdySessionPool::enable_ip_pooling(true);
253 if (parsed_command_line.HasSwitch(switches::kDisableIPPooling))
254 net::SpdySessionPool::enable_ip_pooling(false);
256 if (parsed_command_line.HasSwitch(switches::kMaxSpdySessionsPerDomain)) {
257 int value;
258 base::StringToInt(
259 parsed_command_line.GetSwitchValueASCII(
260 switches::kMaxSpdySessionsPerDomain),
261 &value);
262 net::SpdySessionPool::set_max_sessions_per_domain(value);
265 if (parsed_command_line.HasSwitch(switches::kEnableWebSocketOverSpdy)) {
266 // Enable WebSocket over SPDY.
267 net::WebSocketJob::set_websocket_over_spdy_enabled(true);
270 if (parsed_command_line.HasSwitch(switches::kEnableHttpPipelining))
271 net::HttpStreamFactory::set_http_pipelining_enabled(true);
273 if (parsed_command_line.HasSwitch(switches::kTestingFixedHttpPort)) {
274 int value;
275 base::StringToInt(
276 parsed_command_line.GetSwitchValueASCII(
277 switches::kTestingFixedHttpPort),
278 &value);
279 net::HttpStreamFactory::set_testing_fixed_http_port(value);
282 if (parsed_command_line.HasSwitch(switches::kTestingFixedHttpsPort)) {
283 int value;
284 base::StringToInt(
285 parsed_command_line.GetSwitchValueASCII(
286 switches::kTestingFixedHttpsPort),
287 &value);
288 net::HttpStreamFactory::set_testing_fixed_https_port(value);
292 void InitializeURLRequestThrottlerManager(net::NetLog* net_log) {
293 net::URLRequestThrottlerManager::GetInstance()->set_enable_thread_checks(
294 true);
296 // TODO(joi): Passing the NetLog here is temporary; once I switch the
297 // URLRequestThrottlerManager to be part of the URLRequestContext it will
298 // come from there. Doing it this way for now (2011/5/12) to try to fail
299 // fast in case A/B experiment gives unexpected results.
300 net::URLRequestThrottlerManager::GetInstance()->set_net_log(net_log);
303 // Returns the new local state object, guaranteed non-NULL.
304 PrefService* InitializeLocalState(const CommandLine& parsed_command_line,
305 bool is_first_run) {
306 FilePath local_state_path;
307 PathService::Get(chrome::FILE_LOCAL_STATE, &local_state_path);
308 bool local_state_file_exists = file_util::PathExists(local_state_path);
310 // Load local state. This includes the application locale so we know which
311 // locale dll to load.
312 PrefService* local_state = g_browser_process->local_state();
313 DCHECK(local_state);
315 // TODO(brettw,*): this comment about ResourceBundle was here since
316 // initial commit. This comment seems unrelated, bit-rotten and
317 // a candidate for removal.
318 // Initialize ResourceBundle which handles files loaded from external
319 // sources. This has to be done before uninstall code path and before prefs
320 // are registered.
321 local_state->RegisterStringPref(prefs::kApplicationLocale, std::string());
322 #if defined(OS_CHROMEOS)
323 local_state->RegisterStringPref(prefs::kOwnerLocale, std::string());
324 local_state->RegisterStringPref(prefs::kHardwareKeyboardLayout,
325 std::string());
326 #endif // defined(OS_CHROMEOS)
327 #if !defined(OS_CHROMEOS)
328 local_state->RegisterBooleanPref(prefs::kMetricsReportingEnabled,
329 GoogleUpdateSettings::GetCollectStatsConsent());
330 #endif // !defined(OS_CHROMEOS)
332 if (is_first_run) {
333 #if defined(OS_WIN)
334 // During first run we read the google_update registry key to find what
335 // language the user selected when downloading the installer. This
336 // becomes our default language in the prefs.
337 // Other platforms obey the system locale.
338 std::wstring install_lang;
339 if (GoogleUpdateSettings::GetLanguage(&install_lang)) {
340 local_state->SetString(prefs::kApplicationLocale,
341 WideToASCII(install_lang));
343 #endif // defined(OS_WIN)
346 // If the local state file for the current profile doesn't exist and the
347 // parent profile command line flag is present, then we should inherit some
348 // local state from the parent profile.
349 // Checking that the local state file for the current profile doesn't exist
350 // is the most robust way to determine whether we need to inherit or not
351 // since the parent profile command line flag can be present even when the
352 // current profile is not a new one, and in that case we do not want to
353 // inherit and reset the user's setting.
354 if (!local_state_file_exists &&
355 parsed_command_line.HasSwitch(switches::kParentProfile)) {
356 FilePath parent_profile =
357 parsed_command_line.GetSwitchValuePath(switches::kParentProfile);
358 scoped_ptr<PrefService> parent_local_state(
359 PrefService::CreatePrefService(parent_profile, NULL, false));
360 parent_local_state->RegisterStringPref(prefs::kApplicationLocale,
361 std::string());
362 // Right now, we only inherit the locale setting from the parent profile.
363 local_state->SetString(
364 prefs::kApplicationLocale,
365 parent_local_state->GetString(prefs::kApplicationLocale));
368 #if defined(OS_CHROMEOS)
369 if (parsed_command_line.HasSwitch(switches::kLoginManager)) {
370 std::string owner_locale = local_state->GetString(prefs::kOwnerLocale);
371 // Ensure that we start with owner's locale.
372 if (!owner_locale.empty() &&
373 local_state->GetString(prefs::kApplicationLocale) != owner_locale &&
374 !local_state->IsManagedPreference(prefs::kApplicationLocale)) {
375 local_state->SetString(prefs::kApplicationLocale, owner_locale);
378 #endif
380 return local_state;
383 // Initializes the profile, possibly doing some user prompting to pick a
384 // fallback profile. Returns the newly created profile, or NULL if startup
385 // should not continue.
386 Profile* CreateProfile(const content::MainFunctionParams& parameters,
387 const FilePath& user_data_dir,
388 const CommandLine& parsed_command_line) {
389 Profile* profile;
390 if (ProfileManager::IsMultipleProfilesEnabled() &&
391 parsed_command_line.HasSwitch(switches::kProfileDirectory)) {
392 g_browser_process->local_state()->SetString(prefs::kProfileLastUsed,
393 parsed_command_line.GetSwitchValueASCII(
394 switches::kProfileDirectory));
395 // Clear kProfilesLastActive since the user only wants to launch a specific
396 // profile.
397 ListPrefUpdate update(g_browser_process->local_state(),
398 prefs::kProfilesLastActive);
399 ListValue* profile_list = update.Get();
400 profile_list->Clear();
402 #if defined(OS_CHROMEOS)
403 // TODO(ivankr): http://crbug.com/83792
404 profile = g_browser_process->profile_manager()->GetDefaultProfile(
405 user_data_dir);
406 #else
407 profile = g_browser_process->profile_manager()->GetLastUsedProfile(
408 user_data_dir);
409 #endif
410 if (profile)
411 return profile;
413 #if defined(OS_WIN)
414 #if defined(USE_AURA)
415 // TODO(beng):
416 NOTIMPLEMENTED();
417 #else
418 // Ideally, we should be able to run w/o access to disk. For now, we
419 // prompt the user to pick a different user-data-dir and restart chrome
420 // with the new dir.
421 // http://code.google.com/p/chromium/issues/detail?id=11510
422 FilePath new_user_data_dir = UserDataDirDialog::RunUserDataDirDialog(
423 user_data_dir);
424 if (!parameters.ui_task && browser_shutdown::delete_resources_on_shutdown) {
425 // Only delete the resources if we're not running tests. If we're running
426 // tests the resources need to be reused as many places in the UI cache
427 // SkBitmaps from the ResourceBundle.
428 ResourceBundle::CleanupSharedInstance();
431 if (!new_user_data_dir.empty()) {
432 // Because of the way CommandLine parses, it's sufficient to append a new
433 // --user-data-dir switch. The last flag of the same name wins.
434 // TODO(tc): It would be nice to remove the flag we don't want, but that
435 // sounds risky if we parse differently than CommandLineToArgvW.
436 CommandLine new_command_line = parameters.command_line;
437 new_command_line.AppendSwitchPath(switches::kUserDataDir,
438 new_user_data_dir);
439 base::LaunchProcess(new_command_line, base::LaunchOptions(), NULL);
441 #endif
442 #else
443 // TODO(port): fix this. See comments near the definition of
444 // user_data_dir. It is better to CHECK-fail here than it is to
445 // silently exit because of missing code in the above test.
446 CHECK(profile) << "Cannot get default profile.";
447 #endif
449 return NULL;
452 // Load GPU Blacklist, collect preliminary gpu info, and compute preliminary
453 // gpu feature flags.
454 void InitializeGpuDataManager(const CommandLine& parsed_command_line) {
455 GpuDataManager::GetInstance();
457 if (parsed_command_line.HasSwitch(switches::kSkipGpuDataLoading))
458 return;
460 const base::StringPiece gpu_blacklist_json(
461 ResourceBundle::GetSharedInstance().GetRawDataResource(
462 IDR_GPU_BLACKLIST));
463 chrome::VersionInfo version_info;
464 std::string chrome_version_string =
465 version_info.is_valid() ? version_info.Version() : "0";
466 GpuBlacklist* gpu_blacklist = new GpuBlacklist(chrome_version_string);
467 bool succeed = gpu_blacklist->LoadGpuBlacklist(
468 gpu_blacklist_json.as_string(), GpuBlacklist::kCurrentOsOnly);
469 DCHECK(succeed);
470 GpuDataManager::GetInstance()->SetGpuBlacklist(gpu_blacklist);
473 #if defined(OS_MACOSX)
474 OSStatus KeychainCallback(SecKeychainEvent keychain_event,
475 SecKeychainCallbackInfo* info, void* context) {
476 return noErr;
478 #endif
480 #if defined(OS_CHROMEOS) && defined(TOOLKIT_USES_GTK)
481 void RegisterTranslateableItems(void) {
482 struct {
483 const char* stock_id;
484 int resource_id;
485 } translations[] = {
486 { GTK_STOCK_COPY, IDS_COPY },
487 { GTK_STOCK_CUT, IDS_CUT },
488 { GTK_STOCK_PASTE, IDS_PASTE },
489 { GTK_STOCK_DELETE, IDS_DELETE },
490 { GTK_STOCK_SELECT_ALL, IDS_SELECT_ALL },
491 { NULL, -1 }
492 }, *trans;
494 for (trans = translations; trans->stock_id; trans++) {
495 GtkStockItem stock_item;
496 if (gtk_stock_lookup(trans->stock_id, &stock_item)) {
497 std::string trans_label = gfx::ConvertAcceleratorsFromWindowsStyle(
498 l10n_util::GetStringUTF8(trans->resource_id));
499 stock_item.label = g_strdup(trans_label.c_str());
500 gtk_stock_add(&stock_item, 1);
501 g_free(stock_item.label);
505 #endif // defined(OS_CHROMEOS)
507 void SetSocketReusePolicy(int warmest_socket_trial_group,
508 const int socket_policy[],
509 int num_groups) {
510 const int* result = std::find(socket_policy, socket_policy + num_groups,
511 warmest_socket_trial_group);
512 DCHECK_NE(result, socket_policy + num_groups)
513 << "Not a valid socket reuse policy group";
514 net::SetSocketReusePolicy(result - socket_policy);
517 #if defined(USE_LINUX_BREAKPAD)
518 bool IsCrashReportingEnabled(const PrefService* local_state) {
519 // Check whether we should initialize the crash reporter. It may be disabled
520 // through configuration policy or user preference. It must be disabled for
521 // Guest mode on Chrome OS in Stable channel.
522 // The kHeadless environment variable overrides the decision, but only if the
523 // crash service is under control of the user. It is used by QA testing
524 // infrastructure to switch on generation of crash reports.
525 #if defined(OS_CHROMEOS)
526 bool is_guest_session =
527 CommandLine::ForCurrentProcess()->HasSwitch(switches::kGuestSession);
528 bool is_stable_channel =
529 chrome::VersionInfo::GetChannel() == chrome::VersionInfo::CHANNEL_STABLE;
530 // TODO(pastarmovj): Consider the TrustedGet here.
531 bool reporting_enabled;
532 chromeos::CrosSettings::Get()->GetBoolean(chromeos::kStatsReportingPref,
533 &reporting_enabled);
534 bool breakpad_enabled =
535 !(is_guest_session && is_stable_channel) && reporting_enabled;
536 if (!breakpad_enabled)
537 breakpad_enabled = getenv(env_vars::kHeadless) != NULL;
538 #else
539 const PrefService::Preference* metrics_reporting_enabled =
540 local_state->FindPreference(prefs::kMetricsReportingEnabled);
541 CHECK(metrics_reporting_enabled);
542 bool breakpad_enabled =
543 local_state->GetBoolean(prefs::kMetricsReportingEnabled);
544 if (!breakpad_enabled && metrics_reporting_enabled->IsUserModifiable())
545 breakpad_enabled = getenv(env_vars::kHeadless) != NULL;
546 #endif // #if defined(OS_CHROMEOS)
547 return breakpad_enabled;
549 #endif // #if defined(USE_LINUX_BREAKPAD)
551 // This code is specific to the Windows-only PreReadExperiment field-trial.
552 void AddPreReadHistogramTime(const char* name, base::TimeDelta time) {
553 const base::TimeDelta kMin(base::TimeDelta::FromMilliseconds(1));
554 const base::TimeDelta kMax(base::TimeDelta::FromHours(1));
555 static const size_t kBuckets(100);
557 // FactoryTimeGet will always return a pointer to the same histogram object,
558 // keyed on its name. There's no need for us to store it explicitly anywhere.
559 base::Histogram* counter = base::Histogram::FactoryTimeGet(
560 name, kMin, kMax, kBuckets, base::Histogram::kUmaTargetedHistogramFlag);
562 counter->AddTime(time);
565 } // namespace
567 namespace chrome_browser {
568 // This error message is not localized because we failed to load the
569 // localization data files.
570 const char kMissingLocaleDataTitle[] = "Missing File Error";
571 const char kMissingLocaleDataMessage[] =
572 "Unable to find locale data files. Please reinstall.";
573 } // namespace chrome_browser
575 // BrowserMainParts ------------------------------------------------------------
577 ChromeBrowserMainParts::ChromeBrowserMainParts(
578 const content::MainFunctionParams& parameters)
579 : parameters_(parameters),
580 parsed_command_line_(parameters.command_line),
581 result_code_(content::RESULT_CODE_NORMAL_EXIT),
582 startup_watcher_(new StartupTimeBomb()),
583 shutdown_watcher_(new ShutdownWatcherHelper()),
584 record_search_engine_(false),
585 translate_manager_(NULL),
586 profile_(NULL),
587 run_message_loop_(true),
588 notify_result_(ProcessSingleton::PROCESS_NONE),
589 is_first_run_(false),
590 first_run_ui_bypass_(false),
591 local_state_(NULL),
592 restart_last_session_(false) {
593 // If we're running tests (ui_task is non-null).
594 if (parameters.ui_task)
595 browser_defaults::enable_help_app = false;
598 ChromeBrowserMainParts::~ChromeBrowserMainParts() {
599 for (int i = static_cast<int>(chrome_extra_parts_.size())-1; i >= 0; --i)
600 delete chrome_extra_parts_[i];
601 chrome_extra_parts_.clear();
604 // This will be called after the command-line has been mutated by about:flags
605 void ChromeBrowserMainParts::SetupMetricsAndFieldTrials() {
606 // Must initialize metrics after labs have been converted into switches,
607 // but before field trials are set up (so that client ID is available for
608 // one-time randomized field trials).
609 #if defined(OS_WIN)
610 if (parsed_command_line_.HasSwitch(switches::kChromeFrame))
611 MetricsLog::set_version_extension("-F");
612 #elif defined(ARCH_CPU_64_BITS)
613 MetricsLog::set_version_extension("-64");
614 #endif // defined(OS_WIN)
616 // Initialize FieldTrialList to support FieldTrials that use one-time
617 // randomization. The client ID will be empty if the user has not opted
618 // to send metrics.
619 MetricsService* metrics = browser_process_->metrics_service();
620 field_trial_list_.reset(new base::FieldTrialList(metrics->GetClientId()));
622 SetupFieldTrials(metrics->recording_active(),
623 local_state_->IsManagedPreference(
624 prefs::kMaxConnectionsPerProxy));
626 // Initialize FieldTrialSynchronizer system. This is a singleton and is used
627 // for posting tasks via base::Bind. Its deleted when it goes out of scope.
628 // Even though base::Bind does AddRef and Release, the object will not be
629 // deleted after the Task is executed.
630 field_trial_synchronizer_ = new FieldTrialSynchronizer();
633 // This is an A/B test for the maximum number of persistent connections per
634 // host. Currently Chrome, Firefox, and IE8 have this value set at 6. Safari
635 // uses 4, and Fasterfox (a plugin for Firefox that supposedly configures it to
636 // run faster) uses 8. We would like to see how much of an effect this value has
637 // on browsing. Too large a value might cause us to run into SYN flood detection
638 // mechanisms.
639 void ChromeBrowserMainParts::ConnectionFieldTrial() {
640 const base::FieldTrial::Probability kConnectDivisor = 100;
641 const base::FieldTrial::Probability kConnectProbability = 1; // 1% prob.
643 // After June 30, 2011 builds, it will always be in default group.
644 scoped_refptr<base::FieldTrial> connect_trial(
645 new base::FieldTrial(
646 "ConnCountImpact", kConnectDivisor, "conn_count_6", 2011, 6, 30));
648 // This (6) is the current default value. Having this group declared here
649 // makes it straightforward to modify |kConnectProbability| such that the same
650 // probability value will be assigned to all the other groups, while
651 // preserving the remainder of the of probability space to the default value.
652 const int connect_6 = connect_trial->kDefaultGroupNumber;
654 const int connect_5 = connect_trial->AppendGroup("conn_count_5",
655 kConnectProbability);
656 const int connect_7 = connect_trial->AppendGroup("conn_count_7",
657 kConnectProbability);
658 const int connect_8 = connect_trial->AppendGroup("conn_count_8",
659 kConnectProbability);
660 const int connect_9 = connect_trial->AppendGroup("conn_count_9",
661 kConnectProbability);
663 const int connect_trial_group = connect_trial->group();
665 if (connect_trial_group == connect_5) {
666 net::ClientSocketPoolManager::set_max_sockets_per_group(5);
667 } else if (connect_trial_group == connect_6) {
668 net::ClientSocketPoolManager::set_max_sockets_per_group(6);
669 } else if (connect_trial_group == connect_7) {
670 net::ClientSocketPoolManager::set_max_sockets_per_group(7);
671 } else if (connect_trial_group == connect_8) {
672 net::ClientSocketPoolManager::set_max_sockets_per_group(8);
673 } else if (connect_trial_group == connect_9) {
674 net::ClientSocketPoolManager::set_max_sockets_per_group(9);
675 } else {
676 NOTREACHED();
680 // A/B test for determining a value for unused socket timeout. Currently the
681 // timeout defaults to 10 seconds. Having this value set too low won't allow us
682 // to take advantage of idle sockets. Setting it to too high could possibly
683 // result in more ERR_CONNECTION_RESETs, since some servers will kill a socket
684 // before we time it out. Since these are "unused" sockets, we won't retry the
685 // connection and instead show an error to the user. So we need to be
686 // conservative here. We've seen that some servers will close the socket after
687 // as short as 10 seconds. See http://crbug.com/84313 for more details.
688 void ChromeBrowserMainParts::SocketTimeoutFieldTrial() {
689 const base::FieldTrial::Probability kIdleSocketTimeoutDivisor = 100;
690 // 1% probability for all experimental settings.
691 const base::FieldTrial::Probability kSocketTimeoutProbability = 1;
693 // After June 30, 2011 builds, it will always be in default group.
694 scoped_refptr<base::FieldTrial> socket_timeout_trial(
695 new base::FieldTrial("IdleSktToImpact", kIdleSocketTimeoutDivisor,
696 "idle_timeout_10", 2011, 6, 30));
697 const int socket_timeout_10 = socket_timeout_trial->kDefaultGroupNumber;
699 const int socket_timeout_5 =
700 socket_timeout_trial->AppendGroup("idle_timeout_5",
701 kSocketTimeoutProbability);
702 const int socket_timeout_20 =
703 socket_timeout_trial->AppendGroup("idle_timeout_20",
704 kSocketTimeoutProbability);
706 const int idle_to_trial_group = socket_timeout_trial->group();
708 if (idle_to_trial_group == socket_timeout_5) {
709 net::ClientSocketPool::set_unused_idle_socket_timeout(
710 base::TimeDelta::FromSeconds(5));
711 } else if (idle_to_trial_group == socket_timeout_10) {
712 net::ClientSocketPool::set_unused_idle_socket_timeout(
713 base::TimeDelta::FromSeconds(10));
714 } else if (idle_to_trial_group == socket_timeout_20) {
715 net::ClientSocketPool::set_unused_idle_socket_timeout(
716 base::TimeDelta::FromSeconds(20));
717 } else {
718 NOTREACHED();
722 void ChromeBrowserMainParts::ProxyConnectionsFieldTrial() {
723 const base::FieldTrial::Probability kProxyConnectionsDivisor = 100;
724 // 25% probability
725 const base::FieldTrial::Probability kProxyConnectionProbability = 1;
727 // After June 30, 2011 builds, it will always be in default group.
728 scoped_refptr<base::FieldTrial> proxy_connection_trial(
729 new base::FieldTrial("ProxyConnectionImpact", kProxyConnectionsDivisor,
730 "proxy_connections_32", 2011, 6, 30));
732 // This (32 connections per proxy server) is the current default value.
733 // Declaring it here allows us to easily re-assign the probability space while
734 // maintaining that the default group always has the remainder of the "share",
735 // which allows for cleaner and quicker changes down the line if needed.
736 const int proxy_connections_32 = proxy_connection_trial->kDefaultGroupNumber;
738 // The number of max sockets per group cannot be greater than the max number
739 // of sockets per proxy server. We tried using 8, and it can easily
740 // lead to total browser stalls.
741 const int proxy_connections_16 =
742 proxy_connection_trial->AppendGroup("proxy_connections_16",
743 kProxyConnectionProbability);
744 const int proxy_connections_64 =
745 proxy_connection_trial->AppendGroup("proxy_connections_64",
746 kProxyConnectionProbability);
748 const int proxy_connections_trial_group = proxy_connection_trial->group();
750 if (proxy_connections_trial_group == proxy_connections_16) {
751 net::ClientSocketPoolManager::set_max_sockets_per_proxy_server(16);
752 } else if (proxy_connections_trial_group == proxy_connections_32) {
753 net::ClientSocketPoolManager::set_max_sockets_per_proxy_server(32);
754 } else if (proxy_connections_trial_group == proxy_connections_64) {
755 net::ClientSocketPoolManager::set_max_sockets_per_proxy_server(64);
756 } else {
757 NOTREACHED();
761 // When --use-spdy not set, users will be in A/B test for spdy.
762 // group A (npn_with_spdy): this means npn and spdy are enabled. In case server
763 // supports spdy, browser will use spdy.
764 // group B (npn_with_http): this means npn is enabled but spdy won't be used.
765 // Http is still used for all requests.
766 // default group: no npn or spdy is involved. The "old" non-spdy
767 // chrome behavior.
768 void ChromeBrowserMainParts::SpdyFieldTrial() {
769 if (parsed_command_line().HasSwitch(switches::kUseSpdy)) {
770 std::string spdy_mode =
771 parsed_command_line().GetSwitchValueASCII(switches::kUseSpdy);
772 net::HttpNetworkLayer::EnableSpdy(spdy_mode);
773 } else {
774 #if !defined(OS_CHROMEOS)
775 bool is_spdy_trial = false;
776 const base::FieldTrial::Probability kSpdyDivisor = 100;
777 base::FieldTrial::Probability npnhttp_probability = 5;
779 // After June 30, 2013 builds, it will always be in default group.
780 scoped_refptr<base::FieldTrial> trial(
781 new base::FieldTrial(
782 "SpdyImpact", kSpdyDivisor, "npn_with_spdy", 2013, 6, 30));
784 // npn with spdy support is the default.
785 int npn_spdy_grp = trial->kDefaultGroupNumber;
787 // npn with only http support, no spdy.
788 int npn_http_grp = trial->AppendGroup("npn_with_http", npnhttp_probability);
790 int trial_grp = trial->group();
791 if (trial_grp == npn_http_grp) {
792 is_spdy_trial = true;
793 net::HttpNetworkLayer::EnableSpdy("npn-http");
794 } else if (trial_grp == npn_spdy_grp) {
795 is_spdy_trial = true;
796 net::HttpNetworkLayer::EnableSpdy("npn");
797 } else {
798 CHECK(!is_spdy_trial);
800 #else
801 // Always enable SPDY on Chrome OS
802 net::HttpNetworkLayer::EnableSpdy("npn");
803 #endif // !defined(OS_CHROMEOS)
806 // Setup SPDY CWND Field trial.
807 const base::FieldTrial::Probability kSpdyCwndDivisor = 100;
808 const base::FieldTrial::Probability kSpdyCwnd16 = 20; // fixed at 16
809 const base::FieldTrial::Probability kSpdyCwnd10 = 20; // fixed at 10
810 const base::FieldTrial::Probability kSpdyCwndMin16 = 20; // no less than 16
811 const base::FieldTrial::Probability kSpdyCwndMin10 = 20; // no less than 10
813 // After June 30, 2013 builds, it will always be in default group
814 // (cwndDynamic).
815 scoped_refptr<base::FieldTrial> trial(
816 new base::FieldTrial(
817 "SpdyCwnd", kSpdyCwndDivisor, "cwndDynamic", 2013, 6, 30));
819 trial->AppendGroup("cwnd10", kSpdyCwnd10);
820 trial->AppendGroup("cwnd16", kSpdyCwnd16);
821 trial->AppendGroup("cwndMin16", kSpdyCwndMin16);
822 trial->AppendGroup("cwndMin10", kSpdyCwndMin10);
824 if (parsed_command_line().HasSwitch(switches::kMaxSpdyConcurrentStreams)) {
825 int value = 0;
826 base::StringToInt(parsed_command_line().GetSwitchValueASCII(
827 switches::kMaxSpdyConcurrentStreams),
828 &value);
829 if (value > 0)
830 net::SpdySession::set_max_concurrent_streams(value);
834 // If --socket-reuse-policy is not specified, run an A/B test for choosing the
835 // warmest socket.
836 void ChromeBrowserMainParts::WarmConnectionFieldTrial() {
837 const CommandLine& command_line = parsed_command_line();
838 if (command_line.HasSwitch(switches::kSocketReusePolicy)) {
839 std::string socket_reuse_policy_str = command_line.GetSwitchValueASCII(
840 switches::kSocketReusePolicy);
841 int policy = -1;
842 base::StringToInt(socket_reuse_policy_str, &policy);
844 const int policy_list[] = { 0, 1, 2 };
845 VLOG(1) << "Setting socket_reuse_policy = " << policy;
846 SetSocketReusePolicy(policy, policy_list, arraysize(policy_list));
847 return;
850 const base::FieldTrial::Probability kWarmSocketDivisor = 100;
851 const base::FieldTrial::Probability kWarmSocketProbability = 33;
853 // After January 30, 2013 builds, it will always be in default group.
854 scoped_refptr<base::FieldTrial> warmest_socket_trial(
855 new base::FieldTrial(
856 "WarmSocketImpact", kWarmSocketDivisor, "last_accessed_socket",
857 2013, 1, 30));
859 // Default value is USE_LAST_ACCESSED_SOCKET.
860 const int last_accessed_socket = warmest_socket_trial->kDefaultGroupNumber;
861 const int warmest_socket = warmest_socket_trial->AppendGroup(
862 "warmest_socket", kWarmSocketProbability);
863 const int warm_socket = warmest_socket_trial->AppendGroup(
864 "warm_socket", kWarmSocketProbability);
866 const int warmest_socket_trial_group = warmest_socket_trial->group();
868 const int policy_list[] = { warmest_socket, warm_socket,
869 last_accessed_socket };
870 SetSocketReusePolicy(warmest_socket_trial_group, policy_list,
871 arraysize(policy_list));
874 // If neither --enable-connect-backup-jobs or --disable-connect-backup-jobs is
875 // specified, run an A/B test for automatically establishing backup TCP
876 // connections when a certain timeout value is exceeded.
877 void ChromeBrowserMainParts::ConnectBackupJobsFieldTrial() {
878 if (parsed_command_line().HasSwitch(switches::kEnableConnectBackupJobs)) {
879 net::internal::ClientSocketPoolBaseHelper::set_connect_backup_jobs_enabled(
880 true);
881 } else if (parsed_command_line().HasSwitch(
882 switches::kDisableConnectBackupJobs)) {
883 net::internal::ClientSocketPoolBaseHelper::set_connect_backup_jobs_enabled(
884 false);
885 } else {
886 const base::FieldTrial::Probability kConnectBackupJobsDivisor = 100;
887 // 1% probability.
888 const base::FieldTrial::Probability kConnectBackupJobsProbability = 1;
889 // After June 30, 2011 builds, it will always be in default group.
890 scoped_refptr<base::FieldTrial> trial(
891 new base::FieldTrial("ConnnectBackupJobs",
892 kConnectBackupJobsDivisor, "ConnectBackupJobsEnabled", 2011, 6,
893 30));
894 const int connect_backup_jobs_enabled = trial->kDefaultGroupNumber;
895 trial->AppendGroup("ConnectBackupJobsDisabled",
896 kConnectBackupJobsProbability);
897 const int trial_group = trial->group();
898 net::internal::ClientSocketPoolBaseHelper::set_connect_backup_jobs_enabled(
899 trial_group == connect_backup_jobs_enabled);
903 void ChromeBrowserMainParts::PredictorFieldTrial() {
904 const base::FieldTrial::Probability kDivisor = 1000;
905 // For each option (i.e., non-default), we have a fixed probability.
906 // 0.1% probability.
907 const base::FieldTrial::Probability kProbabilityPerGroup = 1;
909 // After June 30, 2011 builds, it will always be in default group
910 // (default_enabled_prefetch).
911 scoped_refptr<base::FieldTrial> trial(
912 new base::FieldTrial("DnsImpact", kDivisor,
913 "default_enabled_prefetch", 2011, 10, 30));
915 // First option is to disable prefetching completely.
916 int disabled_prefetch = trial->AppendGroup("disabled_prefetch",
917 kProbabilityPerGroup);
919 // We're running two experiments at the same time. The first set of trials
920 // modulates the delay-time until we declare a congestion event (and purge
921 // our queue). The second modulates the number of concurrent resolutions
922 // we do at any time. Users are in exactly one trial (or the default) during
923 // any one run, and hence only one experiment at a time.
924 // Experiment 1:
925 // Set congestion detection at 250, 500, or 750ms, rather than the 1 second
926 // default.
927 int max_250ms_prefetch = trial->AppendGroup("max_250ms_queue_prefetch",
928 kProbabilityPerGroup);
929 int max_500ms_prefetch = trial->AppendGroup("max_500ms_queue_prefetch",
930 kProbabilityPerGroup);
931 int max_750ms_prefetch = trial->AppendGroup("max_750ms_queue_prefetch",
932 kProbabilityPerGroup);
933 // Set congestion detection at 2 seconds instead of the 1 second default.
934 int max_2s_prefetch = trial->AppendGroup("max_2s_queue_prefetch",
935 kProbabilityPerGroup);
936 // Experiment 2:
937 // Set max simultaneous resoultions to 2, 4, or 6, and scale the congestion
938 // limit proportionally (so we don't impact average probability of asserting
939 // congesion very much).
940 int max_2_concurrent_prefetch = trial->AppendGroup(
941 "max_2 concurrent_prefetch", kProbabilityPerGroup);
942 int max_4_concurrent_prefetch = trial->AppendGroup(
943 "max_4 concurrent_prefetch", kProbabilityPerGroup);
944 int max_6_concurrent_prefetch = trial->AppendGroup(
945 "max_6 concurrent_prefetch", kProbabilityPerGroup);
947 if (trial->group() != disabled_prefetch) {
948 // Initialize the DNS prefetch system.
949 size_t max_parallel_resolves =
950 chrome_browser_net::Predictor::kMaxSpeculativeParallelResolves;
951 int max_queueing_delay_ms =
952 chrome_browser_net::Predictor::kMaxSpeculativeResolveQueueDelayMs;
954 if (trial->group() == max_2_concurrent_prefetch)
955 max_parallel_resolves = 2;
956 else if (trial->group() == max_4_concurrent_prefetch)
957 max_parallel_resolves = 4;
958 else if (trial->group() == max_6_concurrent_prefetch)
959 max_parallel_resolves = 6;
960 chrome_browser_net::Predictor::set_max_parallel_resolves(
961 max_parallel_resolves);
963 if (trial->group() == max_250ms_prefetch) {
964 max_queueing_delay_ms =
965 (250 * chrome_browser_net::Predictor::kTypicalSpeculativeGroupSize) /
966 max_parallel_resolves;
967 } else if (trial->group() == max_500ms_prefetch) {
968 max_queueing_delay_ms =
969 (500 * chrome_browser_net::Predictor::kTypicalSpeculativeGroupSize) /
970 max_parallel_resolves;
971 } else if (trial->group() == max_750ms_prefetch) {
972 max_queueing_delay_ms =
973 (750 * chrome_browser_net::Predictor::kTypicalSpeculativeGroupSize) /
974 max_parallel_resolves;
975 } else if (trial->group() == max_2s_prefetch) {
976 max_queueing_delay_ms =
977 (2000 * chrome_browser_net::Predictor::kTypicalSpeculativeGroupSize) /
978 max_parallel_resolves;
980 chrome_browser_net::Predictor::set_max_queueing_delay(
981 max_queueing_delay_ms);
985 void ChromeBrowserMainParts::DefaultAppsFieldTrial() {
986 std::string brand;
987 google_util::GetBrand(&brand);
989 // Create a 100% field trial based on the brand code.
990 if (LowerCaseEqualsASCII(brand, "ecdb")) {
991 base::FieldTrialList::CreateFieldTrial(kDefaultAppsTrialName,
992 kDefaultAppsTrialNoAppsGroup);
993 } else if (LowerCaseEqualsASCII(brand, "ecda")) {
994 base::FieldTrialList::CreateFieldTrial(kDefaultAppsTrialName,
995 kDefaultAppsTrialWithAppsGroup);
999 void ChromeBrowserMainParts::AutoLaunchChromeFieldTrial() {
1000 std::string brand;
1001 google_util::GetBrand(&brand);
1003 // Create a 100% field trial based on the brand code.
1004 if (auto_launch_trial::IsInExperimentGroup(brand)) {
1005 base::FieldTrialList::CreateFieldTrial(kAutoLaunchTrialName,
1006 kAutoLaunchTrialAutoLaunchGroup);
1007 } else if (auto_launch_trial::IsInControlGroup(brand)) {
1008 base::FieldTrialList::CreateFieldTrial(kAutoLaunchTrialName,
1009 kAutoLaunchTrialControlGroup);
1013 // ChromeBrowserMainParts: |SetupMetricsAndFieldTrials()| related --------------
1015 void ChromeBrowserMainParts::SetupFieldTrials(bool metrics_recording_enabled,
1016 bool proxy_policy_is_set) {
1017 // Note: make sure to call ConnectionFieldTrial() before
1018 // ProxyConnectionsFieldTrial().
1019 ConnectionFieldTrial();
1020 SocketTimeoutFieldTrial();
1021 // If a policy is defining the number of active connections this field test
1022 // shoud not be performed.
1023 if (!proxy_policy_is_set)
1024 ProxyConnectionsFieldTrial();
1025 prerender::ConfigurePrefetchAndPrerender(parsed_command_line());
1026 InstantFieldTrial::Activate();
1027 SpdyFieldTrial();
1028 ConnectBackupJobsFieldTrial();
1029 WarmConnectionFieldTrial();
1030 PredictorFieldTrial();
1031 DefaultAppsFieldTrial();
1032 AutoLaunchChromeFieldTrial();
1033 AutocompleteFieldTrial::Activate();
1034 sync_promo_trial::Activate();
1035 NewTabUI::SetupFieldTrials();
1038 void ChromeBrowserMainParts::StartMetricsRecording() {
1039 MetricsService* metrics = g_browser_process->metrics_service();
1040 if (parsed_command_line_.HasSwitch(switches::kMetricsRecordingOnly) ||
1041 parsed_command_line_.HasSwitch(switches::kEnableBenchmarking)) {
1042 // If we're testing then we don't care what the user preference is, we turn
1043 // on recording, but not reporting, otherwise tests fail.
1044 metrics->StartRecordingOnly();
1045 return;
1048 // If the user permits metrics reporting with the checkbox in the
1049 // prefs, we turn on recording. We disable metrics completely for
1050 // non-official builds.
1051 #if defined(GOOGLE_CHROME_BUILD)
1052 #if defined(OS_CHROMEOS)
1053 bool enabled;
1054 chromeos::CrosSettings::Get()->GetBoolean(chromeos::kStatsReportingPref,
1055 &enabled);
1056 #else
1057 bool enabled = local_state_->GetBoolean(prefs::kMetricsReportingEnabled);
1058 #endif // #if defined(OS_CHROMEOS)
1059 if (enabled) {
1060 metrics->Start();
1062 #endif // defined(GOOGLE_CHROME_BUILD)
1065 // -----------------------------------------------------------------------------
1066 // TODO(viettrungluu): move more/rest of BrowserMain() into BrowserMainParts.
1068 #if defined(OS_WIN)
1069 #define DLLEXPORT __declspec(dllexport)
1071 // We use extern C for the prototype DLLEXPORT to avoid C++ name mangling.
1072 extern "C" {
1073 DLLEXPORT void __cdecl RelaunchChromeBrowserWithNewCommandLineIfNeeded();
1076 DLLEXPORT void __cdecl RelaunchChromeBrowserWithNewCommandLineIfNeeded() {
1077 // Need an instance of AtExitManager to handle singleton creations and
1078 // deletions. We need this new instance because, the old instance created
1079 // in ChromeMain() got destructed when the function returned.
1080 base::AtExitManager exit_manager;
1081 upgrade_util::RelaunchChromeBrowserWithNewCommandLineIfNeeded();
1083 #endif
1085 // content::BrowserMainParts implementation ------------------------------------
1087 void ChromeBrowserMainParts::PreEarlyInitialization() {
1088 for (size_t i = 0; i < chrome_extra_parts_.size(); ++i)
1089 chrome_extra_parts_[i]->PreEarlyInitialization();
1092 void ChromeBrowserMainParts::PostEarlyInitialization() {
1093 for (size_t i = 0; i < chrome_extra_parts_.size(); ++i)
1094 chrome_extra_parts_[i]->PostEarlyInitialization();
1097 void ChromeBrowserMainParts::ToolkitInitialized() {
1098 for (size_t i = 0; i < chrome_extra_parts_.size(); ++i)
1099 chrome_extra_parts_[i]->ToolkitInitialized();
1102 void ChromeBrowserMainParts::PreMainMessageLoopStart() {
1103 for (size_t i = 0; i < chrome_extra_parts_.size(); ++i)
1104 chrome_extra_parts_[i]->PreMainMessageLoopStart();
1107 void ChromeBrowserMainParts::PostMainMessageLoopStart() {
1108 for (size_t i = 0; i < chrome_extra_parts_.size(); ++i)
1109 chrome_extra_parts_[i]->PostMainMessageLoopStart();
1112 int ChromeBrowserMainParts::PreCreateThreads() {
1113 result_code_ = PreCreateThreadsImpl();
1114 return result_code_;
1117 int ChromeBrowserMainParts::PreCreateThreadsImpl() {
1118 run_message_loop_ = false;
1119 #if defined(OS_WIN)
1120 PathService::Get(chrome::DIR_USER_DATA, &user_data_dir_);
1121 #else
1122 // Getting the user data dir can fail if the directory isn't
1123 // creatable, for example; on Windows in code below we bring up a
1124 // dialog prompting the user to pick a different directory.
1125 // However, ProcessSingleton needs a real user_data_dir on Mac/Linux,
1126 // so it's better to fail here than fail mysteriously elsewhere.
1127 CHECK(PathService::Get(chrome::DIR_USER_DATA, &user_data_dir_))
1128 << "Must be able to get user data directory!";
1129 #endif
1131 process_singleton_.reset(new ProcessSingleton(user_data_dir_));
1133 is_first_run_ = first_run::IsChromeFirstRun() ||
1134 parsed_command_line().HasSwitch(switches::kFirstRun);
1136 if (parsed_command_line().HasSwitch(switches::kImport) ||
1137 parsed_command_line().HasSwitch(switches::kImportFromFile)) {
1138 // We use different BrowserProcess when importing so no GoogleURLTracker is
1139 // instantiated (as it makes a net::URLRequest and we don't have an IO
1140 // thread, see bug #1292702).
1141 browser_process_.reset(new FirstRunBrowserProcess(parsed_command_line()));
1142 is_first_run_ = false;
1143 } else {
1144 browser_process_.reset(new BrowserProcessImpl(parsed_command_line()));
1147 if (parsed_command_line().HasSwitch(switches::kEnableProfiling)) {
1148 // User wants to override default tracking status.
1149 std::string flag =
1150 parsed_command_line().GetSwitchValueASCII(switches::kEnableProfiling);
1151 bool enabled = flag.compare("0") != 0;
1152 tracked_objects::ThreadData::InitializeAndSetTrackingStatus(enabled);
1155 // This forces the TabCloseableStateWatcher to be created and, on chromeos,
1156 // register for the notifications it needs to track the closeable state of
1157 // tabs.
1158 browser_process_->tab_closeable_state_watcher();
1160 local_state_ = InitializeLocalState(parsed_command_line(),
1161 is_first_run_);
1163 // If we're running tests (ui_task is non-null), then the ResourceBundle
1164 // has already been initialized.
1165 if (parameters().ui_task) {
1166 browser_process_->SetApplicationLocale("en-US");
1167 } else {
1168 // Mac starts it earlier in |PreMainMessageLoopStart()| (because it is
1169 // needed when loading the MainMenu.nib and the language doesn't depend on
1170 // anything since it comes from Cocoa.
1171 #if defined(OS_MACOSX)
1172 browser_process_->SetApplicationLocale(l10n_util::GetLocaleOverride());
1173 #else
1174 const std::string locale =
1175 local_state_->GetString(prefs::kApplicationLocale);
1176 // On a POSIX OS other than ChromeOS, the parameter that is passed to the
1177 // method InitSharedInstance is ignored.
1178 const std::string loaded_locale =
1179 ResourceBundle::InitSharedInstanceWithLocale(locale);
1180 if (loaded_locale.empty() &&
1181 !parsed_command_line().HasSwitch(switches::kNoErrorDialogs)) {
1182 ShowMissingLocaleMessageBox();
1183 return chrome::RESULT_CODE_MISSING_DATA;
1185 CHECK(!loaded_locale.empty()) << "Locale could not be found for " << locale;
1186 browser_process_->SetApplicationLocale(loaded_locale);
1188 FilePath resources_pack_path;
1189 PathService::Get(chrome::FILE_RESOURCES_PACK, &resources_pack_path);
1190 ResourceBundle::AddDataPackToSharedInstance(resources_pack_path);
1191 #endif // defined(OS_MACOSX)
1194 #if defined(TOOLKIT_GTK)
1195 g_set_application_name(l10n_util::GetStringUTF8(IDS_PRODUCT_NAME).c_str());
1196 #endif
1198 // These members must be initialized before returning from this function.
1199 master_prefs_.reset(new first_run::MasterPrefs);
1200 browser_init_.reset(new BrowserInit);
1202 std::string try_chrome =
1203 parsed_command_line().GetSwitchValueASCII(switches::kTryChromeAgain);
1204 if (!try_chrome.empty()) {
1205 #if defined(OS_WIN) && !defined(USE_AURA)
1206 // Setup.exe has determined that we need to run a retention experiment
1207 // and has lauched chrome to show the experiment UI.
1208 if (process_singleton_->FoundOtherProcessWindow()) {
1209 // It seems that we don't need to run the experiment since chrome
1210 // in the same profile is already running.
1211 VLOG(1) << "Retention experiment not required";
1212 return TryChromeDialogView::NOT_NOW;
1214 int try_chrome_int;
1215 base::StringToInt(try_chrome, &try_chrome_int);
1216 TryChromeDialogView::Result answer =
1217 TryChromeDialogView::Show(try_chrome_int, process_singleton_.get());
1218 if (answer == TryChromeDialogView::NOT_NOW)
1219 return chrome::RESULT_CODE_NORMAL_EXIT_CANCEL;
1220 if (answer == TryChromeDialogView::UNINSTALL_CHROME)
1221 return chrome::RESULT_CODE_NORMAL_EXIT_EXP2;
1222 #else
1223 // We don't support retention experiments on Mac or Linux.
1224 return content::RESULT_CODE_NORMAL_EXIT;
1225 #endif // defined(OS_WIN)
1228 #if defined(OS_CHROMEOS) && defined(TOOLKIT_USES_GTK)
1229 // This needs to be called after the locale has been set.
1230 RegisterTranslateableItems();
1231 #endif
1233 // On first run, we need to process the predictor preferences before the
1234 // browser's profile_manager object is created, but after ResourceBundle
1235 // is initialized.
1236 first_run_ui_bypass_ = false; // True to skip first run UI.
1237 if (is_first_run_) {
1238 first_run_ui_bypass_ = !FirstRun::ProcessMasterPreferences(
1239 user_data_dir_, master_prefs_.get());
1240 AddFirstRunNewTabs(browser_init_.get(), master_prefs_->new_tabs);
1242 // If we are running in App mode, we do not want to show the importer
1243 // (first run) UI.
1244 if (!first_run_ui_bypass_ &&
1245 (parsed_command_line().HasSwitch(switches::kApp) ||
1246 parsed_command_line().HasSwitch(switches::kAppId) ||
1247 parsed_command_line().HasSwitch(switches::kNoFirstRun)))
1248 first_run_ui_bypass_ = true;
1250 // Create Sentinel if no-first-run argument is passed in.
1251 if (parsed_command_line().HasSwitch(switches::kNoFirstRun))
1252 first_run::CreateSentinel();
1255 // TODO(viettrungluu): why don't we run this earlier?
1256 if (!parsed_command_line().HasSwitch(switches::kNoErrorDialogs))
1257 WarnAboutMinimumSystemRequirements();
1259 // Convert active labs into switches. Modifies the current command line.
1260 about_flags::ConvertFlagsToSwitches(local_state_,
1261 CommandLine::ForCurrentProcess());
1262 local_state_->UpdateCommandLinePrefStore(CommandLine::ForCurrentProcess());
1264 // Reset the command line in the crash report details, since we may have
1265 // just changed it to include experiments.
1266 child_process_logging::SetCommandLine(CommandLine::ForCurrentProcess());
1268 #if defined(OS_LINUX) || defined(OS_OPENBSD)
1269 // Set the product channel for crash reports.
1270 child_process_logging::SetChannel(
1271 chrome::VersionInfo::GetVersionStringModifier());
1272 #endif
1274 InitializeNetworkOptions(parsed_command_line());
1275 InitializeURLRequestThrottlerManager(browser_process_->net_log());
1277 // Initialize histogram synchronizer system. This is a singleton and is used
1278 // for posting tasks via base::Bind. Its deleted when it goes out of scope.
1279 // Even though base::Bind does AddRef and Release, the object will not
1280 // be deleted after the Task is executed.
1281 histogram_synchronizer_ = new HistogramSynchronizer();
1282 tracking_synchronizer_ = new chrome_browser_metrics::TrackingSynchronizer();
1284 // Now that all preferences have been registered, set the install date
1285 // for the uninstall metrics if this is our first run. This only actually
1286 // gets used if the user has metrics reporting enabled at uninstall time.
1287 int64 install_date =
1288 local_state_->GetInt64(prefs::kUninstallMetricsInstallDate);
1289 if (install_date == 0) {
1290 local_state_->SetInt64(prefs::kUninstallMetricsInstallDate,
1291 base::Time::Now().ToTimeT());
1294 #if defined(OS_MACOSX)
1295 // Get the Keychain API to register for distributed notifications on the main
1296 // thread, which has a proper CFRunloop, instead of later on the I/O thread,
1297 // which doesn't. This ensures those notifications will get delivered
1298 // properly. See issue 37766.
1299 // (Note that the callback mask here is empty. I don't want to register for
1300 // any callbacks, I just want to initialize the mechanism.)
1301 SecKeychainAddCallback(&KeychainCallback, 0, NULL);
1302 #endif
1304 // Now the command line has been mutated based on about:flags, we can setup
1305 // metrics and initialize field trials. The field trials are needed by
1306 // IOThread's initialization which happens in BrowserProcess:PreCreateThreads.
1307 SetupMetricsAndFieldTrials();
1309 // ChromeOS needs ResourceBundle::InitSharedInstance to be called before this.
1310 browser_process_->PreCreateThreads();
1312 return content::RESULT_CODE_NORMAL_EXIT;
1315 void ChromeBrowserMainParts::PreMainMessageLoopRun() {
1316 result_code_ = PreMainMessageLoopRunImpl();
1318 for (size_t i = 0; i < chrome_extra_parts_.size(); ++i)
1319 chrome_extra_parts_[i]->PreMainMessageLoopRun();
1322 // PreMainMessageLoopRun calls these extra stages in the following order:
1323 // PreMainMessageLoopRunImpl()
1324 // ... initial setup, including browser_process_ setup.
1325 // PreProfileInit()
1326 // ... additional setup, including CreateProfile()
1327 // PostProfileInit()
1328 // ... additional setup
1329 // PreBrowserStart()
1330 // ... browser_init_->Start (OR parameters().ui_task->Run())
1331 // PostBrowserStart()
1333 void ChromeBrowserMainParts::PreProfileInit() {
1334 for (size_t i = 0; i < chrome_extra_parts_.size(); ++i)
1335 chrome_extra_parts_[i]->PreProfileInit();
1338 void ChromeBrowserMainParts::PostProfileInit() {
1339 for (size_t i = 0; i < chrome_extra_parts_.size(); ++i)
1340 chrome_extra_parts_[i]->PostProfileInit();
1343 void ChromeBrowserMainParts::PreBrowserStart() {
1344 for (size_t i = 0; i < chrome_extra_parts_.size(); ++i)
1345 chrome_extra_parts_[i]->PreBrowserStart();
1348 void ChromeBrowserMainParts::PostBrowserStart() {
1349 for (size_t i = 0; i < chrome_extra_parts_.size(); ++i)
1350 chrome_extra_parts_[i]->PostBrowserStart();
1353 int ChromeBrowserMainParts::PreMainMessageLoopRunImpl() {
1354 // Now that the file thread has been started, start recording.
1355 StartMetricsRecording();
1357 #if defined(USE_LINUX_BREAKPAD)
1358 // Needs to be called after we have chrome::DIR_USER_DATA and
1359 // g_browser_process. This happens in PreCreateThreads.
1360 BrowserThread::PostTask(BrowserThread::FILE,
1361 FROM_HERE,
1362 base::Bind(&GetLinuxDistroCallback));
1364 if (IsCrashReportingEnabled(local_state_))
1365 InitCrashReporter();
1366 #endif
1368 // Create watchdog thread after creating all other threads because it will
1369 // watch the other threads and they must be running.
1370 browser_process_->watchdog_thread();
1372 // Do any initializating in the browser process that requires all threads
1373 // running.
1374 browser_process_->PreMainMessageLoopRun();
1376 // Record last shutdown time into a histogram.
1377 browser_shutdown::ReadLastShutdownInfo();
1379 #if defined(OS_WIN)
1380 // On Windows, we use our startup as an opportunity to do upgrade/uninstall
1381 // tasks. Those care whether the browser is already running. On Linux/Mac,
1382 // upgrade/uninstall happen separately.
1383 bool already_running = browser_util::IsBrowserAlreadyRunning();
1385 // If the command line specifies 'uninstall' then we need to work here
1386 // unless we detect another chrome browser running.
1387 if (parsed_command_line().HasSwitch(switches::kUninstall)) {
1388 return DoUninstallTasks(already_running);
1391 if (parsed_command_line().HasSwitch(switches::kHideIcons) ||
1392 parsed_command_line().HasSwitch(switches::kShowIcons)) {
1393 return ChromeBrowserMainPartsWin::HandleIconsCommands(
1394 parsed_command_line_);
1396 #endif
1398 if (parsed_command_line().HasSwitch(switches::kMakeDefaultBrowser)) {
1399 return ShellIntegration::SetAsDefaultBrowser() ?
1400 static_cast<int>(content::RESULT_CODE_NORMAL_EXIT) :
1401 static_cast<int>(chrome::RESULT_CODE_SHELL_INTEGRATION_FAILED);
1404 // If the command line specifies --pack-extension, attempt the pack extension
1405 // startup action and exit.
1406 if (parsed_command_line().HasSwitch(switches::kPackExtension)) {
1407 ExtensionsStartupUtil extension_startup_util;
1408 if (extension_startup_util.PackExtension(parsed_command_line()))
1409 return content::RESULT_CODE_NORMAL_EXIT;
1410 return chrome::RESULT_CODE_PACK_EXTENSION_ERROR;
1413 #if !defined(OS_MACOSX)
1414 // In environments other than Mac OS X we support import of settings
1415 // from other browsers. In case this process is a short-lived "import"
1416 // process that another browser runs just to import the settings, we
1417 // don't want to be checking for another browser process, by design.
1418 if (!(parsed_command_line().HasSwitch(switches::kImport) ||
1419 parsed_command_line().HasSwitch(switches::kImportFromFile))) {
1420 #endif
1421 // When another process is running, use that process instead of starting a
1422 // new one. NotifyOtherProcess will currently give the other process up to
1423 // 20 seconds to respond. Note that this needs to be done before we attempt
1424 // to read the profile.
1425 notify_result_ = process_singleton_->NotifyOtherProcessOrCreate();
1426 switch (notify_result_) {
1427 case ProcessSingleton::PROCESS_NONE:
1428 // No process already running, fall through to starting a new one.
1429 break;
1431 case ProcessSingleton::PROCESS_NOTIFIED:
1432 #if defined(OS_POSIX) && !defined(OS_MACOSX)
1433 printf("%s\n", base::SysWideToNativeMB(UTF16ToWide(
1434 l10n_util::GetStringUTF16(IDS_USED_EXISTING_BROWSER))).c_str());
1435 #endif
1436 return content::RESULT_CODE_NORMAL_EXIT;
1438 case ProcessSingleton::PROFILE_IN_USE:
1439 return chrome::RESULT_CODE_PROFILE_IN_USE;
1441 case ProcessSingleton::LOCK_ERROR:
1442 LOG(ERROR) << "Failed to create a ProcessSingleton for your profile "
1443 "directory. This means that running multiple instances "
1444 "would start multiple browser processes rather than "
1445 "opening a new window in the existing process. Aborting "
1446 "now to avoid profile corruption.";
1447 return chrome::RESULT_CODE_PROFILE_IN_USE;
1449 default:
1450 NOTREACHED();
1452 #if !defined(OS_MACOSX) // closing brace for if
1454 #endif
1456 #if defined(USE_X11)
1457 SetBrowserX11ErrorHandlers();
1458 #endif
1460 // Desktop construction occurs here, (required before profile creation).
1461 PreProfileInit();
1463 // Profile creation ----------------------------------------------------------
1465 if (is_first_run_) {
1466 // Warn the ProfileManager that an import process will run, possibly
1467 // locking the WebDataService directory of the next Profile created.
1468 browser_process_->profile_manager()->SetWillImport();
1471 profile_ = CreateProfile(parameters(), user_data_dir_, parsed_command_line());
1472 if (!profile_)
1473 return content::RESULT_CODE_NORMAL_EXIT;
1475 // Autoload any profiles which are running background apps.
1476 // TODO(rlp): Do this on a separate thread. See http://crbug.com/99075.
1477 if (!BackgroundModeManager::IsBackgroundModePermanentlyDisabled(
1478 &parsed_command_line())) {
1479 browser_process_->profile_manager()->AutoloadProfiles();
1481 // Post-profile init ---------------------------------------------------------
1483 #if !defined(OS_MACOSX)
1484 // Importing other browser settings is done in a browser-like process
1485 // that exits when this task has finished.
1486 // TODO(port): Port the Mac's IPC-based implementation to other platforms to
1487 // replace this implementation. http://crbug.com/22142
1488 if (parsed_command_line().HasSwitch(switches::kImport) ||
1489 parsed_command_line().HasSwitch(switches::kImportFromFile)) {
1490 return first_run::ImportNow(profile_, parsed_command_line());
1492 #endif
1494 #if defined(OS_WIN)
1495 // Do the tasks if chrome has been upgraded while it was last running.
1496 if (!already_running && upgrade_util::DoUpgradeTasks(parsed_command_line()))
1497 return content::RESULT_CODE_NORMAL_EXIT;
1499 // Check if there is any machine level Chrome installed on the current
1500 // machine. If yes and the current Chrome process is user level, we do not
1501 // allow the user level Chrome to run. So we notify the user and uninstall
1502 // user level Chrome.
1503 // Note this check should only happen here, after all the checks above
1504 // (uninstall, resource bundle initialization, other chrome browser
1505 // processes etc).
1506 // Do not allow this to occur for Chrome Frame user-to-system handoffs.
1507 if (!parsed_command_line().HasSwitch(switches::kChromeFrame) &&
1508 ChromeBrowserMainPartsWin::CheckMachineLevelInstall()) {
1509 return chrome::RESULT_CODE_MACHINE_LEVEL_INSTALL_EXISTS;
1511 #endif
1513 // Create the TranslateManager singleton.
1514 translate_manager_ = TranslateManager::GetInstance();
1515 DCHECK(translate_manager_ != NULL);
1517 #if defined(OS_MACOSX)
1518 if (!parsed_command_line().HasSwitch(switches::kNoFirstRun)) {
1519 // Disk image installation is sort of a first-run task, so it shares the
1520 // kNoFirstRun switch.
1521 if (MaybeInstallFromDiskImage()) {
1522 // The application was installed and the installed copy has been
1523 // launched. This process is now obsolete. Exit.
1524 return content::RESULT_CODE_NORMAL_EXIT;
1527 #endif
1529 // TODO(stevenjb): Move WIN and MACOSX specific code to apprpriate Parts.
1530 // (requires supporting early exit).
1531 PostProfileInit();
1533 // Show the First Run UI if this is the first time Chrome has been run on
1534 // this computer, or we're being compelled to do so by a command line flag.
1535 // Note that this be done _after_ the PrefService is initialized and all
1536 // preferences are registered, since some of the code that the importer
1537 // touches reads preferences.
1538 if (is_first_run_) {
1539 if (!first_run_ui_bypass_) {
1540 first_run::AutoImport(profile_,
1541 master_prefs_->homepage_defined,
1542 master_prefs_->do_import_items,
1543 master_prefs_->dont_import_items,
1544 master_prefs_->make_chrome_default,
1545 process_singleton_.get());
1546 #if defined(OS_POSIX)
1547 // On Windows, the download is tagged with enable/disable stats so there
1548 // is no need for this code.
1550 // If stats reporting was turned on by the first run dialog then toggle
1551 // the pref.
1552 if (GoogleUpdateSettings::GetCollectStatsConsent())
1553 local_state_->SetBoolean(prefs::kMetricsReportingEnabled, true);
1554 #endif // OS_POSIX
1555 } // if (!first_run_ui_bypass_)
1557 Browser::SetNewHomePagePrefs(profile_->GetPrefs());
1558 browser_process_->profile_manager()->OnImportFinished(profile_);
1559 } // if (is_first_run_)
1561 #if defined(OS_WIN)
1562 // Sets things up so that if we crash from this point on, a dialog will
1563 // popup asking the user to restart chrome. It is done this late to avoid
1564 // testing against a bunch of special cases that are taken care early on.
1565 ChromeBrowserMainPartsWin::PrepareRestartOnCrashEnviroment(
1566 parsed_command_line());
1568 // Registers Chrome with the Windows Restart Manager, which will restore the
1569 // Chrome session when the computer is restarted after a system update.
1570 // This could be run as late as WM_QUERYENDSESSION for system update reboots,
1571 // but should run on startup if extended to handle crashes/hangs/patches.
1572 // Also, better to run once here than once for each HWND's WM_QUERYENDSESSION.
1573 if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
1574 ChromeBrowserMainPartsWin::RegisterApplicationRestart(
1575 parsed_command_line());
1578 #if defined(GOOGLE_CHROME_BUILD)
1579 // Init the RLZ library. This just binds the dll and schedules a task on the
1580 // file thread to be run sometime later. If this is the first run we record
1581 // the installation event.
1582 bool google_search_default = false;
1583 TemplateURLService* template_url_service =
1584 TemplateURLServiceFactory::GetForProfile(profile_);
1585 if (template_url_service) {
1586 const TemplateURL* url_template =
1587 template_url_service->GetDefaultSearchProvider();
1588 if (url_template) {
1589 const TemplateURLRef* urlref = url_template->url();
1590 if (urlref) {
1591 google_search_default = urlref->HasGoogleBaseURLs();
1596 bool google_search_homepage = false;
1597 PrefService* pref_service = profile_->GetPrefs();
1598 if (pref_service) {
1599 std::string homepage = pref_service->GetString(prefs::kHomePage);
1600 google_search_homepage = google_util::IsGoogleHomePageUrl(homepage);
1603 RLZTracker::InitRlzDelayed(is_first_run_, master_prefs_->ping_delay,
1604 google_search_default, google_search_homepage);
1606 // Prime the RLZ cache for the home page access point so that its avaiable
1607 // for the startup page if needed (i.e., when the startup page is set to
1608 // the home page).
1609 RLZTracker::GetAccessPointRlz(rlz_lib::CHROME_HOME_PAGE, NULL);
1610 #endif // GOOGLE_CHROME_BUILD
1611 #endif // OS_WIN
1613 // Configure modules that need access to resources.
1614 net::NetModule::SetResourceProvider(chrome_common_net::NetResourceProvider);
1616 // In unittest mode, this will do nothing. In normal mode, this will create
1617 // the global GoogleURLTracker and IntranetRedirectDetector instances, which
1618 // will promptly go to sleep for five and seven seconds, respectively (to
1619 // avoid slowing startup), and wake up afterwards to see if they should do
1620 // anything else.
1622 // A simpler way of doing all this would be to have some function which could
1623 // give the time elapsed since startup, and simply have these objects check
1624 // that when asked to initialize themselves, but this doesn't seem to exist.
1626 // These can't be created in the BrowserProcessImpl constructor because they
1627 // need to read prefs that get set after that runs.
1628 browser_process_->google_url_tracker();
1629 browser_process_->intranet_redirect_detector();
1631 // Disable SDCH filtering if switches::kEnableSdch is 0.
1632 int sdch_enabled = 1;
1633 if (parsed_command_line().HasSwitch(switches::kEnableSdch)) {
1634 base::StringToInt(parsed_command_line().GetSwitchValueASCII(
1635 switches::kEnableSdch), &sdch_enabled);
1636 if (!sdch_enabled)
1637 net::SdchManager::EnableSdchSupport(false);
1639 if (sdch_enabled) {
1640 // Perform A/B test to measure global impact of SDCH support.
1641 // Set up a field trial to see what disabling SDCH does to latency of page
1642 // layout globally.
1643 base::FieldTrial::Probability kSDCH_DIVISOR = 1000;
1644 base::FieldTrial::Probability kSDCH_DISABLE_PROBABILITY = 1; // 0.1% prob.
1645 // After March 31, 2012 builds, it will always be in default group.
1646 scoped_refptr<base::FieldTrial> sdch_trial(
1647 new base::FieldTrial("GlobalSdch", kSDCH_DIVISOR, "global_enable_sdch",
1648 2012, 3, 31));
1649 int sdch_enabled_group = sdch_trial->kDefaultGroupNumber;
1651 sdch_trial->AppendGroup("global_disable_sdch",
1652 kSDCH_DISABLE_PROBABILITY);
1653 if (sdch_enabled_group != sdch_trial->group())
1654 net::SdchManager::EnableSdchSupport(false);
1657 if (parsed_command_line().HasSwitch(switches::kEnableWatchdog))
1658 InstallJankometer(parsed_command_line());
1660 #if defined(OS_WIN) && !defined(GOOGLE_CHROME_BUILD)
1661 if (parsed_command_line().HasSwitch(switches::kDebugPrint)) {
1662 FilePath path =
1663 parsed_command_line().GetSwitchValuePath(switches::kDebugPrint);
1664 printing::PrintedDocument::set_debug_dump_path(path);
1666 #endif
1668 HandleTestParameters(parsed_command_line());
1669 RecordBreakpadStatusUMA(browser_process_->metrics_service());
1670 about_flags::RecordUMAStatistics(local_state_);
1671 LanguageUsageMetrics::RecordAcceptLanguages(
1672 profile_->GetPrefs()->GetString(prefs::kAcceptLanguages));
1673 LanguageUsageMetrics::RecordApplicationLanguage(
1674 browser_process_->GetApplicationLocale());
1676 // The extension service may be available at this point. If the command line
1677 // specifies --uninstall-extension, attempt the uninstall extension startup
1678 // action.
1679 if (parsed_command_line().HasSwitch(switches::kUninstallExtension)) {
1680 ExtensionsStartupUtil ext_startup_util;
1681 if (ext_startup_util.UninstallExtension(parsed_command_line(), profile_))
1682 return content::RESULT_CODE_NORMAL_EXIT;
1683 return chrome::RESULT_CODE_UNINSTALL_EXTENSION_ERROR;
1686 // Start watching for hangs during startup. We disarm this hang detector when
1687 // ThreadWatcher takes over or when browser is shutdown or when
1688 // startup_watcher_ is deleted.
1689 startup_watcher_->Arm(base::TimeDelta::FromSeconds(300));
1691 // Start watching for a hang.
1692 MetricsService::LogNeedForCleanShutdown();
1694 #if defined(OS_WIN)
1695 // We check this here because if the profile is OTR (chromeos possibility)
1696 // it won't still be accessible after browser is destroyed.
1697 record_search_engine_ = is_first_run_ && !profile_->IsOffTheRecord();
1698 #endif
1700 // Create the instance of the cloud print proxy service so that it can launch
1701 // the service process if needed. This is needed because the service process
1702 // might have shutdown because an update was available.
1703 // TODO(torne): this should maybe be done with
1704 // ProfileKeyedServiceFactory::ServiceIsCreatedWithProfile() instead?
1705 CloudPrintProxyServiceFactory::GetForProfile(profile_);
1707 // Load GPU Blacklist.
1708 InitializeGpuDataManager(parsed_command_line());
1710 // Start watching all browser threads for responsiveness.
1711 ThreadWatcherList::StartWatchingAll(parsed_command_line());
1713 #if !defined(DISABLE_NACL)
1714 NaClProcessHost::EarlyStartup();
1715 #endif
1717 PreBrowserStart();
1719 // Instantiate the notification UI manager, as this triggers a perf timer
1720 // used to measure startup time. TODO(stevenjb): Figure out what is actually
1721 // triggering the timer and call that explicitly in the approprate place.
1722 // http://crbug.com/105065.
1723 browser_process_->notification_ui_manager();
1725 if (parameters().ui_task) {
1726 // We are in test mode. Run one task and enter the main message loop.
1727 #if defined(OS_MACOSX)
1728 if (parameters().autorelease_pool)
1729 parameters().autorelease_pool->Recycle();
1730 #endif
1731 parameters().ui_task->Run();
1732 delete parameters().ui_task;
1733 run_message_loop_ = false;
1734 } else {
1735 // Most general initialization is behind us, but opening a
1736 // tab and/or session restore and such is still to be done.
1737 base::TimeTicks browser_open_start = base::TimeTicks::Now();
1739 // We are in regular browser boot sequence. Open initial tabs and enter the
1740 // main message loop.
1741 int result_code;
1742 #if defined(OS_CHROMEOS)
1743 // On ChromeOS multiple profiles doesn't apply, and will break if we load
1744 // them this early as the cryptohome hasn't yet been mounted (which happens
1745 // only once we log in.
1746 std::vector<Profile*> last_opened_profiles;
1747 #else
1748 std::vector<Profile*> last_opened_profiles =
1749 g_browser_process->profile_manager()->GetLastOpenedProfiles();
1750 #endif
1751 if (browser_init_->Start(parsed_command_line(), FilePath(),
1752 profile_, last_opened_profiles, &result_code)) {
1753 #if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS))
1754 // Initialize autoupdate timer. Timer callback costs basically nothing
1755 // when browser is not in persistent mode, so it's OK to let it ride on
1756 // the main thread. This needs to be done here because we don't want
1757 // to start the timer when Chrome is run inside a test harness.
1758 browser_process_->StartAutoupdateTimer();
1759 #endif
1761 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
1762 // On Linux, the running exe will be updated if an upgrade becomes
1763 // available while the browser is running. We need to save the last
1764 // modified time of the exe, so we can compare to determine if there is
1765 // an upgrade while the browser is kept alive by a persistent extension.
1766 upgrade_util::SaveLastModifiedTimeOfExe();
1767 #endif
1769 // Record now as the last successful chrome start.
1770 GoogleUpdateSettings::SetLastRunTime();
1772 #if defined(OS_MACOSX)
1773 // Call Recycle() here as late as possible, before going into the loop
1774 // because Start() will add things to it while creating the main window.
1775 if (parameters().autorelease_pool)
1776 parameters().autorelease_pool->Recycle();
1777 #endif
1779 RecordPreReadExperimentTime("Startup.BrowserOpenTabs",
1780 base::TimeTicks::Now() - browser_open_start);
1782 // TODO(mad): Move this call in a proper place on CrOS.
1783 // http://crosbug.com/17687
1784 #if !defined(OS_CHROMEOS)
1785 // If we're running tests (ui_task is non-null), then we don't want to
1786 // call FetchLanguageListFromTranslateServer
1787 if (parameters().ui_task == NULL && translate_manager_ != NULL) {
1788 // TODO(willchan): Get rid of this after TranslateManager doesn't use
1789 // the default request context. http://crbug.com/89396.
1790 // This is necessary to force |default_request_context_| to be
1791 // initialized.
1792 profile_->GetRequestContext();
1793 translate_manager_->FetchLanguageListFromTranslateServer(
1794 profile_->GetPrefs());
1796 #endif
1798 run_message_loop_ = true;
1799 } else {
1800 run_message_loop_ = false;
1803 browser_init_.reset();
1805 PostBrowserStart();
1807 return result_code_;
1810 bool ChromeBrowserMainParts::MainMessageLoopRun(int* result_code) {
1811 // Set the result code set in PreMainMessageLoopRun or set above.
1812 *result_code = result_code_;
1814 if (!run_message_loop_)
1815 return true; // Don't run the default message loop.
1817 // This should be invoked as close to the start of the browser's
1818 // UI thread message loop as possible to get a stable measurement
1819 // across versions.
1820 RecordBrowserStartupTime();
1822 #if defined(USE_AURA)
1823 aura::RootWindow::GetInstance()->Run();
1824 #elif defined(TOOLKIT_VIEWS)
1825 views::AcceleratorHandler accelerator_handler;
1826 MessageLoopForUI::current()->RunWithDispatcher(&accelerator_handler);
1827 #elif defined(USE_X11)
1828 MessageLoopForUI::current()->RunWithDispatcher(NULL);
1829 #elif defined(OS_POSIX)
1830 MessageLoopForUI::current()->Run();
1831 #endif
1833 return true;
1836 void ChromeBrowserMainParts::PostMainMessageLoopRun() {
1837 // Start watching for jank during shutdown. It gets disarmed when
1838 // |shutdown_watcher_| object is destructed.
1839 shutdown_watcher_->Arm(base::TimeDelta::FromSeconds(300));
1841 // Disarm the startup hang detector time bomb if it is still Arm'ed.
1842 startup_watcher_->Disarm();
1844 for (size_t i = 0; i < chrome_extra_parts_.size(); ++i)
1845 chrome_extra_parts_[i]->PostMainMessageLoopRun();
1847 #if defined(OS_WIN)
1848 // Log the search engine chosen on first run. Do this at shutdown, after any
1849 // changes are made from the first run bubble link, etc.
1850 if (record_search_engine_) {
1851 TemplateURLService* url_service =
1852 TemplateURLServiceFactory::GetForProfile(profile_);
1853 const TemplateURL* default_search_engine =
1854 url_service->GetDefaultSearchProvider();
1855 // The default engine can be NULL if the administrator has disabled
1856 // default search.
1857 SearchEngineType search_engine_type =
1858 default_search_engine ? default_search_engine->search_engine_type() :
1859 SEARCH_ENGINE_OTHER;
1860 // Record the search engine chosen.
1861 UMA_HISTOGRAM_ENUMERATION("Chrome.SearchSelectExempt",
1862 search_engine_type,
1863 SEARCH_ENGINE_MAX);
1865 #endif
1867 // Some tests don't set parameters.ui_task, so they started translate
1868 // language fetch that was never completed so we need to cleanup here
1869 // otherwise it will be done by the destructor in a wrong thread.
1870 if (parameters().ui_task == NULL && translate_manager_ != NULL)
1871 translate_manager_->CleanupPendingUlrFetcher();
1873 if (notify_result_ == ProcessSingleton::PROCESS_NONE)
1874 process_singleton_->Cleanup();
1876 // Stop all tasks that might run on WatchDogThread.
1877 ThreadWatcherList::StopWatchingAll();
1879 browser_process_->metrics_service()->Stop();
1881 restart_last_session_ = browser_shutdown::ShutdownPreThreadsStop();
1882 browser_process_->StartTearDown();
1885 void ChromeBrowserMainParts::PostDestroyThreads() {
1886 browser_process_->PostDestroyThreads();
1887 // browser_shutdown takes care of deleting browser_process, so we need to
1888 // release it.
1889 ignore_result(browser_process_.release());
1890 browser_shutdown::ShutdownPostThreadsStop(restart_last_session_);
1891 master_prefs_.reset();
1892 process_singleton_.reset();
1894 // We need to do this check as late as possible, but due to modularity, this
1895 // may be the last point in Chrome. This would be more effective if done at
1896 // a higher level on the stack, so that it is impossible for an early return
1897 // to bypass this code. Perhaps we need a *final* hook that is called on all
1898 // paths from content/browser/browser_main.
1899 CHECK(MetricsService::UmaMetricsProperlyShutdown());
1902 // Public members:
1904 void ChromeBrowserMainParts::AddParts(ChromeBrowserMainExtraParts* parts) {
1905 chrome_extra_parts_.push_back(parts);
1908 // Misc ------------------------------------------------------------------------
1910 // This code is specific to the Windows-only PreReadExperiment field-trial.
1911 void RecordPreReadExperimentTime(const char* name, base::TimeDelta time) {
1912 DCHECK(name != NULL);
1914 // This gets called with different histogram names, so we don't want to use
1915 // the UMA_HISTOGRAM_CUSTOM_TIMES macro--it uses a static variable, and the
1916 // first call wins.
1917 AddPreReadHistogramTime(name, time);
1919 #if defined(OS_WIN)
1920 #if defined(GOOGLE_CHROME_BUILD)
1921 // The pre-read experiment is Windows and Google Chrome specific.
1922 scoped_ptr<base::Environment> env(base::Environment::Create());
1924 // Only record the sub-histogram result if the experiment is running
1925 // (environment variable is set, and valid).
1926 std::string pre_read;
1927 if (env->GetVar(chrome::kPreReadEnvironmentVariable, &pre_read) &&
1928 (pre_read == "0" || pre_read == "1")) {
1929 std::string uma_name(name);
1931 // We want XP to record a separate histogram, as the loader on XP
1932 // is very different from the Vista and Win7 loaders.
1933 if (base::win::GetVersion() <= base::win::VERSION_XP)
1934 uma_name += "_XP";
1936 uma_name += "_PreRead";
1937 uma_name += pre_read == "1" ? "Enabled" : "Disabled";
1938 AddPreReadHistogramTime(uma_name.c_str(), time);
1940 #endif
1941 #endif