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"
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"
128 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
129 #include "chrome/browser/first_run/upgrade_util_linux.h"
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"
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.
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"
170 #if defined(TOOLKIT_VIEWS)
171 #include "ui/views/focus/accelerator_handler.h"
174 #if defined(TOOLKIT_USES_GTK)
175 #include "chrome/browser/ui/gtk/gtk_util.h"
176 #include "ui/gfx/gtk_util.h"
180 #include "chrome/browser/chrome_browser_main_x11.h"
183 #if defined(USE_AURA)
184 #include "ui/aura/root_window.h"
187 using content::BrowserThread
;
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
)) {
203 // This parameter causes a null pointer crash (crash reporter trigger).
204 if (command_line
.HasSwitch(switches::kBrowserCrashTest
)) {
205 int* bad_pointer
= NULL
;
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());
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
) {
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
)) {
259 parsed_command_line
.GetSwitchValueASCII(
260 switches::kMaxSpdySessionsPerDomain
),
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
)) {
276 parsed_command_line
.GetSwitchValueASCII(
277 switches::kTestingFixedHttpPort
),
279 net::HttpStreamFactory::set_testing_fixed_http_port(value
);
282 if (parsed_command_line
.HasSwitch(switches::kTestingFixedHttpsPort
)) {
285 parsed_command_line
.GetSwitchValueASCII(
286 switches::kTestingFixedHttpsPort
),
288 net::HttpStreamFactory::set_testing_fixed_https_port(value
);
292 void InitializeURLRequestThrottlerManager(net::NetLog
* net_log
) {
293 net::URLRequestThrottlerManager::GetInstance()->set_enable_thread_checks(
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
,
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();
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
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
,
326 #endif // defined(OS_CHROMEOS)
327 #if !defined(OS_CHROMEOS)
328 local_state
->RegisterBooleanPref(prefs::kMetricsReportingEnabled
,
329 GoogleUpdateSettings::GetCollectStatsConsent());
330 #endif // !defined(OS_CHROMEOS)
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
,
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
);
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
) {
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
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(
407 profile
= g_browser_process
->profile_manager()->GetLastUsedProfile(
414 #if defined(USE_AURA)
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
421 // http://code.google.com/p/chromium/issues/detail?id=11510
422 FilePath new_user_data_dir
= UserDataDirDialog::RunUserDataDirDialog(
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
,
439 base::LaunchProcess(new_command_line
, base::LaunchOptions(), NULL
);
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.";
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
))
460 const base::StringPiece
gpu_blacklist_json(
461 ResourceBundle::GetSharedInstance().GetRawDataResource(
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
);
470 GpuDataManager::GetInstance()->SetGpuBlacklist(gpu_blacklist
);
473 #if defined(OS_MACOSX)
474 OSStatus
KeychainCallback(SecKeychainEvent keychain_event
,
475 SecKeychainCallbackInfo
* info
, void* context
) {
480 #if defined(OS_CHROMEOS) && defined(TOOLKIT_USES_GTK)
481 void RegisterTranslateableItems(void) {
483 const char* stock_id
;
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
},
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
[],
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
,
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
;
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
);
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
),
587 run_message_loop_(true),
588 notify_result_(ProcessSingleton::PROCESS_NONE
),
589 is_first_run_(false),
590 first_run_ui_bypass_(false),
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).
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
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
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);
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));
722 void ChromeBrowserMainParts::ProxyConnectionsFieldTrial() {
723 const base::FieldTrial::Probability kProxyConnectionsDivisor
= 100;
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);
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
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
);
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");
798 CHECK(!is_spdy_trial
);
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
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
)) {
826 base::StringToInt(parsed_command_line().GetSwitchValueASCII(
827 switches::kMaxSpdyConcurrentStreams
),
830 net::SpdySession::set_max_concurrent_streams(value
);
834 // If --socket-reuse-policy is not specified, run an A/B test for choosing the
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
);
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
));
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",
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(
881 } else if (parsed_command_line().HasSwitch(
882 switches::kDisableConnectBackupJobs
)) {
883 net::internal::ClientSocketPoolBaseHelper::set_connect_backup_jobs_enabled(
886 const base::FieldTrial::Probability kConnectBackupJobsDivisor
= 100;
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,
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.
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.
925 // Set congestion detection at 250, 500, or 750ms, rather than the 1 second
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
);
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() {
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() {
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();
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();
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)
1054 chromeos::CrosSettings::Get()->GetBoolean(chromeos::kStatsReportingPref
,
1057 bool enabled
= local_state_
->GetBoolean(prefs::kMetricsReportingEnabled
);
1058 #endif // #if defined(OS_CHROMEOS)
1062 #endif // defined(GOOGLE_CHROME_BUILD)
1065 // -----------------------------------------------------------------------------
1066 // TODO(viettrungluu): move more/rest of BrowserMain() into BrowserMainParts.
1069 #define DLLEXPORT __declspec(dllexport)
1071 // We use extern C for the prototype DLLEXPORT to avoid C++ name mangling.
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();
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;
1120 PathService::Get(chrome::DIR_USER_DATA
, &user_data_dir_
);
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!";
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;
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.
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
1158 browser_process_
->tab_closeable_state_watcher();
1160 local_state_
= InitializeLocalState(parsed_command_line(),
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");
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());
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());
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
;
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
;
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();
1233 // On first run, we need to process the predictor preferences before the
1234 // browser's profile_manager object is created, but after ResourceBundle
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
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());
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
);
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.
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,
1362 base::Bind(&GetLinuxDistroCallback
));
1364 if (IsCrashReportingEnabled(local_state_
))
1365 InitCrashReporter();
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
1374 browser_process_
->PreMainMessageLoopRun();
1376 // Record last shutdown time into a histogram.
1377 browser_shutdown::ReadLastShutdownInfo();
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_
);
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
))) {
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.
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());
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
;
1452 #if !defined(OS_MACOSX) // closing brace for if
1456 #if defined(USE_X11)
1457 SetBrowserX11ErrorHandlers();
1460 // Desktop construction occurs here, (required before profile creation).
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());
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());
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
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
;
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
;
1529 // TODO(stevenjb): Move WIN and MACOSX specific code to apprpriate Parts.
1530 // (requires supporting early exit).
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
1552 if (GoogleUpdateSettings::GetCollectStatsConsent())
1553 local_state_
->SetBoolean(prefs::kMetricsReportingEnabled
, true);
1555 } // if (!first_run_ui_bypass_)
1557 Browser::SetNewHomePagePrefs(profile_
->GetPrefs());
1558 browser_process_
->profile_manager()->OnImportFinished(profile_
);
1559 } // if (is_first_run_)
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();
1589 const TemplateURLRef
* urlref
= url_template
->url();
1591 google_search_default
= urlref
->HasGoogleBaseURLs();
1596 bool google_search_homepage
= false;
1597 PrefService
* pref_service
= profile_
->GetPrefs();
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
1609 RLZTracker::GetAccessPointRlz(rlz_lib::CHROME_HOME_PAGE
, NULL
);
1610 #endif // GOOGLE_CHROME_BUILD
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
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
);
1637 net::SdchManager::EnableSdchSupport(false);
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
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",
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
)) {
1663 parsed_command_line().GetSwitchValuePath(switches::kDebugPrint
);
1664 printing::PrintedDocument::set_debug_dump_path(path
);
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
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();
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();
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();
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();
1731 parameters().ui_task
->Run();
1732 delete parameters().ui_task
;
1733 run_message_loop_
= false;
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.
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
;
1748 std::vector
<Profile
*> last_opened_profiles
=
1749 g_browser_process
->profile_manager()->GetLastOpenedProfiles();
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();
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();
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();
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
1792 profile_
->GetRequestContext();
1793 translate_manager_
->FetchLanguageListFromTranslateServer(
1794 profile_
->GetPrefs());
1798 run_message_loop_
= true;
1800 run_message_loop_
= false;
1803 browser_init_
.reset();
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
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();
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();
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
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",
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
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());
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
1917 AddPreReadHistogramTime(name
, time
);
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
)
1936 uma_name
+= "_PreRead";
1937 uma_name
+= pre_read
== "1" ? "Enabled" : "Disabled";
1938 AddPreReadHistogramTime(uma_name
.c_str(), time
);