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_info.h"
21 #include "base/process_util.h"
22 #include "base/run_loop.h"
23 #include "base/string_number_conversions.h"
24 #include "base/string_piece.h"
25 #include "base/string_split.h"
26 #include "base/sys_string_conversions.h"
27 #include "base/threading/platform_thread.h"
28 #include "base/time.h"
29 #include "base/utf_string_conversions.h"
30 #include "base/values.h"
31 #include "build/build_config.h"
32 #include "chrome/browser/about_flags.h"
33 #include "chrome/browser/browser_process.h"
34 #include "chrome/browser/browser_process_impl.h"
35 #include "chrome/browser/browser_shutdown.h"
36 #include "chrome/browser/chrome_browser_main_extra_parts.h"
37 #include "chrome/browser/defaults.h"
38 #include "chrome/browser/extensions/extension_protocols.h"
39 #include "chrome/browser/extensions/extension_service.h"
40 #include "chrome/browser/extensions/extensions_startup.h"
41 #include "chrome/browser/first_run/upgrade_util.h"
42 #include "chrome/browser/google/google_search_counter.h"
43 #include "chrome/browser/google/google_util.h"
44 #include "chrome/browser/gpu_blacklist.h"
45 #include "chrome/browser/jankometer.h"
46 #include "chrome/browser/language_usage_metrics.h"
47 #include "chrome/browser/managed_mode.h"
48 #include "chrome/browser/metrics/field_trial_synchronizer.h"
49 #include "chrome/browser/metrics/metrics_log.h"
50 #include "chrome/browser/metrics/metrics_service.h"
51 #include "chrome/browser/metrics/thread_watcher.h"
52 #include "chrome/browser/metrics/tracking_synchronizer.h"
53 #include "chrome/browser/metrics/variations_service.h"
54 #include "chrome/browser/nacl_host/nacl_process_host.h"
55 #include "chrome/browser/net/chrome_net_log.h"
56 #include "chrome/browser/notifications/desktop_notification_service.h"
57 #include "chrome/browser/notifications/desktop_notification_service_factory.h"
58 #include "chrome/browser/page_cycler/page_cycler.h"
59 #include "chrome/browser/plugin_prefs.h"
60 #include "chrome/browser/prefs/pref_service.h"
61 #include "chrome/browser/prefs/pref_value_store.h"
62 #include "chrome/browser/prefs/scoped_user_pref_update.h"
63 #include "chrome/browser/printing/cloud_print/cloud_print_proxy_service.h"
64 #include "chrome/browser/printing/cloud_print/cloud_print_proxy_service_factory.h"
65 #include "chrome/browser/process_singleton.h"
66 #include "chrome/browser/profiles/profile.h"
67 #include "chrome/browser/profiles/profile_manager.h"
68 #include "chrome/browser/search_engines/search_engine_type.h"
69 #include "chrome/browser/search_engines/template_url.h"
70 #include "chrome/browser/search_engines/template_url_prepopulate_data.h"
71 #include "chrome/browser/search_engines/template_url_service.h"
72 #include "chrome/browser/search_engines/template_url_service_factory.h"
73 #include "chrome/browser/service/service_process_control.h"
74 #include "chrome/browser/shell_integration.h"
75 #include "chrome/browser/translate/translate_manager.h"
76 #include "chrome/browser/ui/browser.h"
77 #include "chrome/browser/ui/browser_finder.h"
78 #include "chrome/browser/ui/browser_ui_prefs.h"
79 #include "chrome/browser/ui/startup/default_browser_prompt.h"
80 #include "chrome/browser/ui/startup/startup_browser_creator.h"
81 #include "chrome/browser/ui/uma_browsing_activity_observer.h"
82 #include "chrome/browser/ui/user_data_dir_dialog.h"
83 #include "chrome/browser/ui/webui/chrome_url_data_manager_backend.h"
84 #include "chrome/common/child_process_logging.h"
85 #include "chrome/common/chrome_constants.h"
86 #include "chrome/common/chrome_paths.h"
87 #include "chrome/common/chrome_result_codes.h"
88 #include "chrome/common/chrome_switches.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/metrics/experiments_helper.h"
94 #include "chrome/common/net/net_resource_provider.h"
95 #include "chrome/common/pref_names.h"
96 #include "chrome/common/profiling.h"
97 #include "chrome/installer/util/google_update_settings.h"
98 #include "content/public/browser/browser_thread.h"
99 #include "content/public/browser/gpu_data_manager.h"
100 #include "content/public/browser/render_process_host.h"
101 #include "content/public/common/content_client.h"
102 #include "content/public/common/main_function_params.h"
103 #include "grit/app_locale_settings.h"
104 #include "grit/browser_resources.h"
105 #include "grit/chromium_strings.h"
106 #include "grit/generated_resources.h"
107 #include "grit/platform_locale_settings.h"
108 #include "net/base/net_module.h"
109 #include "net/base/sdch_manager.h"
110 #include "net/base/ssl_config_service.h"
111 #include "net/cookies/cookie_monster.h"
112 #include "net/http/http_stream_factory.h"
113 #include "net/spdy/spdy_session.h"
114 #include "net/spdy/spdy_session_pool.h"
115 #include "net/url_request/url_request.h"
116 #include "net/websockets/websocket_job.h"
117 #include "ui/base/l10n/l10n_util.h"
118 #include "ui/base/layout.h"
119 #include "ui/base/resource/resource_bundle.h"
120 #include "ui/base/resource/resource_handle.h"
122 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
123 #include "chrome/browser/first_run/upgrade_util_linux.h"
126 #if defined(OS_CHROMEOS)
127 #include "chrome/browser/chromeos/cros/cros_library.h"
128 #include "chrome/browser/chromeos/settings/cros_settings.h"
129 #include "chrome/browser/chromeos/settings/cros_settings_names.h"
132 // TODO(port): several win-only methods have been pulled out of this, but
133 // BrowserMain() as a whole needs to be broken apart so that it's usable by
134 // other platforms. For now, it's just a stub. This is a serious work in
135 // progress and should not be taken as an indication of a real refactoring.
138 #include "base/environment.h" // For PreRead experiment.
139 #include "base/win/windows_version.h"
140 #include "chrome/browser/browser_util_win.h"
141 #include "chrome/browser/chrome_browser_main_win.h"
142 #include "chrome/browser/first_run/try_chrome_dialog_view.h"
143 #include "chrome/browser/first_run/upgrade_util_win.h"
144 #include "chrome/browser/net/url_fixer_upper.h"
145 #include "chrome/browser/ui/network_profile_bubble.h"
146 #include "chrome/installer/util/helper.h"
147 #include "chrome/installer/util/install_util.h"
148 #include "chrome/installer/util/shell_util.h"
149 #include "net/base/net_util.h"
150 #include "printing/printed_document.h"
151 #include "ui/base/l10n/l10n_util_win.h"
152 #include "ui/base/win/dpi.h"
153 #endif // defined(OS_WIN)
155 #if defined(OS_MACOSX)
156 #include <Security/Security.h>
158 #include "base/mac/scoped_nsautorelease_pool.h"
159 #include "chrome/browser/mac/keystone_glue.h"
162 #if defined(ENABLE_RLZ)
163 #include "chrome/browser/rlz/rlz.h"
166 #if defined(TOOLKIT_VIEWS)
167 #include "ui/views/focus/accelerator_handler.h"
171 #include "chrome/browser/chrome_browser_main_x11.h"
174 using content::BrowserThread
;
178 // This function provides some ways to test crash and assertion handling
179 // behavior of the program.
180 void HandleTestParameters(const CommandLine
& command_line
) {
181 // This parameter causes an assertion.
182 if (command_line
.HasSwitch(switches::kBrowserAssertTest
)) {
186 // This parameter causes a null pointer crash (crash reporter trigger).
187 if (command_line
.HasSwitch(switches::kBrowserCrashTest
)) {
188 int* bad_pointer
= NULL
;
193 void AddFirstRunNewTabs(StartupBrowserCreator
* browser_creator
,
194 const std::vector
<GURL
>& new_tabs
) {
195 for (std::vector
<GURL
>::const_iterator it
= new_tabs
.begin();
196 it
!= new_tabs
.end(); ++it
) {
198 browser_creator
->AddFirstRunTab(*it
);
202 void InitializeNetworkOptions(const CommandLine
& parsed_command_line
) {
203 if (parsed_command_line
.HasSwitch(switches::kEnableFileCookies
)) {
204 // Enable cookie storage for file:// URLs. Must do this before the first
205 // Profile (and therefore the first CookieMonster) is created.
206 net::CookieMonster::EnableFileScheme();
209 if (parsed_command_line
.HasSwitch(switches::kIgnoreCertificateErrors
))
210 net::HttpStreamFactory::set_ignore_certificate_errors(true);
212 if (parsed_command_line
.HasSwitch(switches::kHostRules
))
213 net::HttpStreamFactory::SetHostMappingRules(
214 parsed_command_line
.GetSwitchValueASCII(switches::kHostRules
));
216 if (parsed_command_line
.HasSwitch(switches::kEnableIPPooling
))
217 net::SpdySessionPool::enable_ip_pooling(true);
219 if (parsed_command_line
.HasSwitch(switches::kDisableIPPooling
))
220 net::SpdySessionPool::enable_ip_pooling(false);
222 if (parsed_command_line
.HasSwitch(switches::kMaxSpdySessionsPerDomain
)) {
225 parsed_command_line
.GetSwitchValueASCII(
226 switches::kMaxSpdySessionsPerDomain
),
228 net::SpdySessionPool::set_max_sessions_per_domain(value
);
231 if (parsed_command_line
.HasSwitch(switches::kEnableWebSocketOverSpdy
)) {
232 // Enable WebSocket over SPDY.
233 net::WebSocketJob::set_websocket_over_spdy_enabled(true);
236 if (parsed_command_line
.HasSwitch(switches::kEnableHttpPipelining
))
237 net::HttpStreamFactory::set_http_pipelining_enabled(true);
239 if (parsed_command_line
.HasSwitch(switches::kTestingFixedHttpPort
)) {
242 parsed_command_line
.GetSwitchValueASCII(
243 switches::kTestingFixedHttpPort
),
245 net::HttpStreamFactory::set_testing_fixed_http_port(value
);
248 if (parsed_command_line
.HasSwitch(switches::kTestingFixedHttpsPort
)) {
251 parsed_command_line
.GetSwitchValueASCII(
252 switches::kTestingFixedHttpsPort
),
254 net::HttpStreamFactory::set_testing_fixed_https_port(value
);
258 // Returns the new local state object, guaranteed non-NULL.
259 PrefService
* InitializeLocalState(const CommandLine
& parsed_command_line
,
261 FilePath local_state_path
;
262 PathService::Get(chrome::FILE_LOCAL_STATE
, &local_state_path
);
263 bool local_state_file_exists
= file_util::PathExists(local_state_path
);
265 // Load local state. This includes the application locale so we know which
266 // locale dll to load.
267 PrefService
* local_state
= g_browser_process
->local_state();
270 // TODO(brettw,*): this comment about ResourceBundle was here since
271 // initial commit. This comment seems unrelated, bit-rotten and
272 // a candidate for removal.
273 // Initialize ResourceBundle which handles files loaded from external
274 // sources. This has to be done before uninstall code path and before prefs
276 local_state
->RegisterStringPref(prefs::kApplicationLocale
, std::string());
277 #if defined(OS_CHROMEOS)
278 local_state
->RegisterStringPref(prefs::kOwnerLocale
, std::string());
279 local_state
->RegisterStringPref(prefs::kHardwareKeyboardLayout
,
281 #endif // defined(OS_CHROMEOS)
282 #if !defined(OS_CHROMEOS)
283 local_state
->RegisterBooleanPref(prefs::kMetricsReportingEnabled
,
284 GoogleUpdateSettings::GetCollectStatsConsent());
285 #endif // !defined(OS_CHROMEOS)
289 // During first run we read the google_update registry key to find what
290 // language the user selected when downloading the installer. This
291 // becomes our default language in the prefs.
292 // Other platforms obey the system locale.
293 std::wstring install_lang
;
294 if (GoogleUpdateSettings::GetLanguage(&install_lang
)) {
295 local_state
->SetString(prefs::kApplicationLocale
,
296 WideToASCII(install_lang
));
298 #endif // defined(OS_WIN)
301 // If the local state file for the current profile doesn't exist and the
302 // parent profile command line flag is present, then we should inherit some
303 // local state from the parent profile.
304 // Checking that the local state file for the current profile doesn't exist
305 // is the most robust way to determine whether we need to inherit or not
306 // since the parent profile command line flag can be present even when the
307 // current profile is not a new one, and in that case we do not want to
308 // inherit and reset the user's setting.
309 if (!local_state_file_exists
&&
310 parsed_command_line
.HasSwitch(switches::kParentProfile
)) {
311 FilePath parent_profile
=
312 parsed_command_line
.GetSwitchValuePath(switches::kParentProfile
);
313 scoped_ptr
<PrefService
> parent_local_state(
314 PrefService::CreatePrefService(parent_profile
,
315 g_browser_process
->policy_service(),
317 parent_local_state
->RegisterStringPref(prefs::kApplicationLocale
,
319 // Right now, we only inherit the locale setting from the parent profile.
320 local_state
->SetString(
321 prefs::kApplicationLocale
,
322 parent_local_state
->GetString(prefs::kApplicationLocale
));
325 #if defined(OS_CHROMEOS)
326 if (parsed_command_line
.HasSwitch(switches::kLoginManager
)) {
327 std::string owner_locale
= local_state
->GetString(prefs::kOwnerLocale
);
328 // Ensure that we start with owner's locale.
329 if (!owner_locale
.empty() &&
330 local_state
->GetString(prefs::kApplicationLocale
) != owner_locale
&&
331 !local_state
->IsManagedPreference(prefs::kApplicationLocale
)) {
332 local_state
->SetString(prefs::kApplicationLocale
, owner_locale
);
340 // Initializes the profile, possibly doing some user prompting to pick a
341 // fallback profile. Returns the newly created profile, or NULL if startup
342 // should not continue.
343 Profile
* CreateProfile(const content::MainFunctionParams
& parameters
,
344 const FilePath
& user_data_dir
,
345 const CommandLine
& parsed_command_line
) {
347 if (ProfileManager::IsMultipleProfilesEnabled() &&
348 parsed_command_line
.HasSwitch(switches::kProfileDirectory
)) {
349 g_browser_process
->local_state()->SetString(prefs::kProfileLastUsed
,
350 parsed_command_line
.GetSwitchValueASCII(switches::kProfileDirectory
));
351 // Clear kProfilesLastActive since the user only wants to launch a specific
353 ListPrefUpdate
update(g_browser_process
->local_state(),
354 prefs::kProfilesLastActive
);
355 ListValue
* profile_list
= update
.Get();
356 profile_list
->Clear();
358 #if defined(OS_CHROMEOS)
359 // TODO(ivankr): http://crbug.com/83792
360 profile
= g_browser_process
->profile_manager()->GetDefaultProfile(
363 profile
= g_browser_process
->profile_manager()->GetLastUsedProfile(
370 #if defined(USE_AURA)
374 // Ideally, we should be able to run w/o access to disk. For now, we
375 // prompt the user to pick a different user-data-dir and restart chrome
377 // http://code.google.com/p/chromium/issues/detail?id=11510
378 FilePath new_user_data_dir
= chrome::ShowUserDataDirDialog(user_data_dir
);
380 if (!new_user_data_dir
.empty()) {
381 // Because of the way CommandLine parses, it's sufficient to append a new
382 // --user-data-dir switch. The last flag of the same name wins.
383 // TODO(tc): It would be nice to remove the flag we don't want, but that
384 // sounds risky if we parse differently than CommandLineToArgvW.
385 CommandLine new_command_line
= parameters
.command_line
;
386 new_command_line
.AppendSwitchPath(switches::kUserDataDir
,
388 base::LaunchProcess(new_command_line
, base::LaunchOptions(), NULL
);
392 // TODO(port): fix this. See comments near the definition of
393 // user_data_dir. It is better to CHECK-fail here than it is to
394 // silently exit because of missing code in the above test.
395 CHECK(profile
) << "Cannot get default profile.";
401 // Load GPU Blacklist, collect preliminary gpu info, and compute preliminary
402 // gpu feature flags.
403 void InitializeGpuDataManager(const CommandLine
& parsed_command_line
) {
404 content::GpuDataManager::GetInstance();
405 if (parsed_command_line
.HasSwitch(switches::kSkipGpuDataLoading
) ||
406 parsed_command_line
.HasSwitch(switches::kIgnoreGpuBlacklist
)) {
410 const base::StringPiece
gpu_blacklist_json(
411 ResourceBundle::GetSharedInstance().GetRawDataResource(
412 IDR_GPU_BLACKLIST
, ui::SCALE_FACTOR_NONE
));
413 GpuBlacklist
* gpu_blacklist
= GpuBlacklist::GetInstance();
414 bool succeed
= gpu_blacklist
->LoadGpuBlacklist(
415 gpu_blacklist_json
.as_string(), GpuBlacklist::kCurrentOsOnly
);
417 gpu_blacklist
->UpdateGpuDataManager();
420 #if defined(OS_MACOSX)
421 OSStatus
KeychainCallback(SecKeychainEvent keychain_event
,
422 SecKeychainCallbackInfo
* info
, void* context
) {
427 // This code is specific to the Windows-only PreReadExperiment field-trial.
428 void AddPreReadHistogramTime(const char* name
, base::TimeDelta time
) {
429 const base::TimeDelta
kMin(base::TimeDelta::FromMilliseconds(1));
430 const base::TimeDelta
kMax(base::TimeDelta::FromHours(1));
431 static const size_t kBuckets(100);
433 // FactoryTimeGet will always return a pointer to the same histogram object,
434 // keyed on its name. There's no need for us to store it explicitly anywhere.
435 base::Histogram
* counter
= base::Histogram::FactoryTimeGet(
436 name
, kMin
, kMax
, kBuckets
, base::Histogram::kUmaTargetedHistogramFlag
);
438 counter
->AddTime(time
);
441 bool ProcessSingletonNotificationCallback(const CommandLine
& command_line
,
442 const FilePath
& current_directory
) {
443 // Drop the request if the browser process is already in shutdown path.
444 if (!g_browser_process
|| g_browser_process
->IsShuttingDown())
447 // TODO(erikwright): Consider removing this - AFAIK it is no longer used.
448 // Handle the --uninstall-extension startup action. This needs to done here
449 // in the process that is running with the target profile, otherwise the
450 // uninstall will fail to unload and remove all components.
451 if (command_line
.HasSwitch(switches::kUninstallExtension
)) {
452 // The uninstall extension switch can't be combined with the profile
454 DCHECK(!command_line
.HasSwitch(switches::kProfileDirectory
));
456 Profile
* profile
= ProfileManager::GetLastUsedProfile();
458 // We should never be called before the profile has been created.
463 ExtensionsStartupUtil ext_startup_util
;
464 ext_startup_util
.UninstallExtension(command_line
, profile
);
468 StartupBrowserCreator::ProcessCommandLineAlreadyRunning(
469 command_line
, current_directory
);
473 bool HasImportSwitch(const CommandLine
& command_line
) {
474 return (command_line
.HasSwitch(switches::kImport
) ||
475 command_line
.HasSwitch(switches::kImportFromFile
));
480 namespace chrome_browser
{
481 // This error message is not localized because we failed to load the
482 // localization data files.
483 const char kMissingLocaleDataTitle
[] = "Missing File Error";
484 const char kMissingLocaleDataMessage
[] =
485 "Unable to find locale data files. Please reinstall.";
486 } // namespace chrome_browser
488 // BrowserMainParts ------------------------------------------------------------
491 bool ChromeBrowserMainParts::disable_enforcing_cookie_policies_for_tests_
=
494 ChromeBrowserMainParts::ChromeBrowserMainParts(
495 const content::MainFunctionParams
& parameters
)
496 : parameters_(parameters
),
497 parsed_command_line_(parameters
.command_line
),
498 result_code_(content::RESULT_CODE_NORMAL_EXIT
),
499 startup_watcher_(new StartupTimeBomb()),
500 shutdown_watcher_(new ShutdownWatcherHelper()),
501 browser_field_trials_(parameters
.command_line
),
502 record_search_engine_(false),
503 translate_manager_(NULL
),
505 run_message_loop_(true),
506 notify_result_(ProcessSingleton::PROCESS_NONE
),
507 is_first_run_(false),
508 first_run_ui_bypass_(false),
510 restart_last_session_(false) {
511 // If we're running tests (ui_task is non-null).
512 if (parameters
.ui_task
)
513 browser_defaults::enable_help_app
= false;
515 // Chrome disallows cookies by default. All code paths that want to use
516 // cookies need to go through one of Chrome's URLRequestContexts which have
517 // a ChromeNetworkDelegate attached that selectively allows cookies again.
518 if (!disable_enforcing_cookie_policies_for_tests_
)
519 net::URLRequest::SetDefaultCookiePolicyToBlock();
522 ChromeBrowserMainParts::~ChromeBrowserMainParts() {
523 for (int i
= static_cast<int>(chrome_extra_parts_
.size())-1; i
>= 0; --i
)
524 delete chrome_extra_parts_
[i
];
525 chrome_extra_parts_
.clear();
528 // This will be called after the command-line has been mutated by about:flags
529 void ChromeBrowserMainParts::SetupMetricsAndFieldTrials() {
530 // Must initialize metrics after labs have been converted into switches,
531 // but before field trials are set up (so that client ID is available for
532 // one-time randomized field trials).
534 if (parsed_command_line_
.HasSwitch(switches::kChromeFrame
))
535 MetricsLog::set_version_extension("-F");
536 #elif defined(ARCH_CPU_64_BITS)
537 MetricsLog::set_version_extension("-64");
538 #endif // defined(OS_WIN)
540 // Initialize FieldTrialList to support FieldTrials that use one-time
542 MetricsService
* metrics
= browser_process_
->metrics_service();
543 if (IsMetricsReportingEnabled())
544 metrics
->ForceClientIdCreation(); // Needed below.
545 field_trial_list_
.reset(
546 new base::FieldTrialList(metrics
->GetEntropySource()));
548 // Ensure any field trials specified on the command line are initialized.
549 // Also stop the metrics service so that we don't pollute UMA.
551 const CommandLine
* command_line
= CommandLine::ForCurrentProcess();
552 if (command_line
->HasSwitch(switches::kForceFieldTrials
)) {
553 std::string persistent
= command_line
->GetSwitchValueASCII(
554 switches::kForceFieldTrials
);
555 bool ret
= base::FieldTrialList::CreateTrialsFromString(persistent
);
556 CHECK(ret
) << "Invalid --" << switches::kForceFieldTrials
<<
561 chrome_variations::VariationsService
* variations_service
=
562 browser_process_
->variations_service();
563 variations_service
->CreateTrialsFromSeed(browser_process_
->local_state());
565 browser_field_trials_
.SetupFieldTrials(
566 local_state_
->IsManagedPreference(prefs::kMaxConnectionsPerProxy
));
568 SetupPlatformFieldTrials();
570 // Initialize FieldTrialSynchronizer system. This is a singleton and is used
571 // for posting tasks via base::Bind. Its deleted when it goes out of scope.
572 // Even though base::Bind does AddRef and Release, the object will not be
573 // deleted after the Task is executed.
574 field_trial_synchronizer_
= new FieldTrialSynchronizer();
577 // ChromeBrowserMainParts: |SetupMetricsAndFieldTrials()| related --------------
579 void ChromeBrowserMainParts::StartMetricsRecording() {
580 MetricsService
* metrics
= g_browser_process
->metrics_service();
581 if (parsed_command_line_
.HasSwitch(switches::kMetricsRecordingOnly
) ||
582 parsed_command_line_
.HasSwitch(switches::kEnableBenchmarking
)) {
583 // If we're testing then we don't care what the user preference is, we turn
584 // on recording, but not reporting, otherwise tests fail.
585 metrics
->StartRecordingOnly();
589 if (IsMetricsReportingEnabled())
593 bool ChromeBrowserMainParts::IsMetricsReportingEnabled() {
594 // If the user permits metrics reporting with the checkbox in the
595 // prefs, we turn on recording. We disable metrics completely for
596 // non-official builds.
597 bool enabled
= false;
599 // The debug build doesn't send UMA logs when FieldTrials are forced.
600 const CommandLine
* command_line
= CommandLine::ForCurrentProcess();
601 if (command_line
->HasSwitch(switches::kForceFieldTrials
))
603 #endif // #ifndef NDEBUG
605 #if defined(GOOGLE_CHROME_BUILD)
606 #if defined(OS_CHROMEOS)
607 chromeos::CrosSettings::Get()->GetBoolean(chromeos::kStatsReportingPref
,
610 enabled
= local_state_
->GetBoolean(prefs::kMetricsReportingEnabled
);
611 #endif // #if defined(OS_CHROMEOS)
612 #endif // defined(GOOGLE_CHROME_BUILD)
616 // -----------------------------------------------------------------------------
617 // TODO(viettrungluu): move more/rest of BrowserMain() into BrowserMainParts.
620 #define DLLEXPORT __declspec(dllexport)
622 // We use extern C for the prototype DLLEXPORT to avoid C++ name mangling.
624 DLLEXPORT
void __cdecl
RelaunchChromeBrowserWithNewCommandLineIfNeeded();
627 DLLEXPORT
void __cdecl
RelaunchChromeBrowserWithNewCommandLineIfNeeded() {
628 // Need an instance of AtExitManager to handle singleton creations and
629 // deletions. We need this new instance because, the old instance created
630 // in ChromeMain() got destructed when the function returned.
631 base::AtExitManager exit_manager
;
632 upgrade_util::RelaunchChromeBrowserWithNewCommandLineIfNeeded();
636 // content::BrowserMainParts implementation ------------------------------------
638 void ChromeBrowserMainParts::PreEarlyInitialization() {
639 // Single-process is an unsupported and not fully tested mode, so
640 // don't enable it for official Chrome builds (by not setting the client, the
641 #if defined(GOOGLE_CHROME_BUILD)
642 if (content::RenderProcessHost::run_renderer_in_process())
643 content::RenderProcessHost::set_run_renderer_in_process(false);
644 #endif // GOOGLE_CHROME_BUILD
646 for (size_t i
= 0; i
< chrome_extra_parts_
.size(); ++i
)
647 chrome_extra_parts_
[i
]->PreEarlyInitialization();
650 void ChromeBrowserMainParts::PostEarlyInitialization() {
651 for (size_t i
= 0; i
< chrome_extra_parts_
.size(); ++i
)
652 chrome_extra_parts_
[i
]->PostEarlyInitialization();
655 void ChromeBrowserMainParts::ToolkitInitialized() {
656 for (size_t i
= 0; i
< chrome_extra_parts_
.size(); ++i
)
657 chrome_extra_parts_
[i
]->ToolkitInitialized();
660 void ChromeBrowserMainParts::PreMainMessageLoopStart() {
661 for (size_t i
= 0; i
< chrome_extra_parts_
.size(); ++i
)
662 chrome_extra_parts_
[i
]->PreMainMessageLoopStart();
665 void ChromeBrowserMainParts::PostMainMessageLoopStart() {
666 for (size_t i
= 0; i
< chrome_extra_parts_
.size(); ++i
)
667 chrome_extra_parts_
[i
]->PostMainMessageLoopStart();
670 int ChromeBrowserMainParts::PreCreateThreads() {
671 result_code_
= PreCreateThreadsImpl();
672 // These members must be initialized before returning from this function.
673 DCHECK(master_prefs_
.get());
674 DCHECK(browser_creator_
.get());
678 int ChromeBrowserMainParts::PreCreateThreadsImpl() {
679 run_message_loop_
= false;
681 PathService::Get(chrome::DIR_USER_DATA
, &user_data_dir_
);
683 // Getting the user data dir can fail if the directory isn't
684 // creatable, for example; on Windows in code below we bring up a
685 // dialog prompting the user to pick a different directory.
686 // However, ProcessSingleton needs a real user_data_dir on Mac/Linux,
687 // so it's better to fail here than fail mysteriously elsewhere.
688 CHECK(PathService::Get(chrome::DIR_USER_DATA
, &user_data_dir_
))
689 << "Must be able to get user data directory!";
692 process_singleton_
.reset(new ProcessSingleton(user_data_dir_
));
693 // Ensure ProcessSingleton won't process messages too early. It will be
694 // unlocked in PostBrowserStart().
695 process_singleton_
->Lock(NULL
);
698 (first_run::IsChromeFirstRun() ||
699 parsed_command_line().HasSwitch(switches::kFirstRun
)) &&
700 !HasImportSwitch(parsed_command_line());
701 browser_process_
.reset(new BrowserProcessImpl(parsed_command_line()));
703 if (parsed_command_line().HasSwitch(switches::kEnableProfiling
)) {
704 // User wants to override default tracking status.
706 parsed_command_line().GetSwitchValueASCII(switches::kEnableProfiling
);
707 // Default to basic profiling (no parent child support).
708 tracked_objects::ThreadData::Status status
=
709 tracked_objects::ThreadData::PROFILING_ACTIVE
;
710 if (flag
.compare("0") != 0)
711 status
= tracked_objects::ThreadData::DEACTIVATED
;
712 else if (flag
.compare("child") != 0)
713 status
= tracked_objects::ThreadData::PROFILING_CHILDREN_ACTIVE
;
714 tracked_objects::ThreadData::InitializeAndSetTrackingStatus(status
);
717 if (parsed_command_line().HasSwitch(switches::kProfilingOutputFile
)) {
718 tracking_objects_
.set_output_file_path(
719 parsed_command_line().GetSwitchValuePath(
720 switches::kProfilingOutputFile
));
723 local_state_
= InitializeLocalState(parsed_command_line(), is_first_run_
);
725 // These members must be initialized before returning from this function.
726 master_prefs_
.reset(new first_run::MasterPrefs
);
727 browser_creator_
.reset(new StartupBrowserCreator
);
728 chrome::UMABrowsingActivityObserver::Init();
730 // Convert active labs into switches. This needs to be done before
731 // ResourceBundle::InitSharedInstanceWithLocale as some loaded resources are
732 // affected by experiment flags (--touch-optimized-ui in particular). Not
733 // needed on Android as there aren't experimental flags.
734 about_flags::ConvertFlagsToSwitches(local_state_
,
735 CommandLine::ForCurrentProcess());
736 local_state_
->UpdateCommandLinePrefStore(CommandLine::ForCurrentProcess());
738 // Reset the command line in the crash report details, since we may have
739 // just changed it to include experiments.
740 child_process_logging::SetCommandLine(CommandLine::ForCurrentProcess());
742 // If we're running tests (ui_task is non-null), then the ResourceBundle
743 // has already been initialized.
744 if (parameters().ui_task
) {
745 browser_process_
->SetApplicationLocale("en-US");
747 // Mac starts it earlier in |PreMainMessageLoopStart()| (because it is
748 // needed when loading the MainMenu.nib and the language doesn't depend on
749 // anything since it comes from Cocoa.
750 #if defined(OS_MACOSX)
751 browser_process_
->SetApplicationLocale(l10n_util::GetLocaleOverride());
753 const std::string locale
=
754 local_state_
->GetString(prefs::kApplicationLocale
);
755 // On a POSIX OS other than ChromeOS, the parameter that is passed to the
756 // method InitSharedInstance is ignored.
757 const std::string loaded_locale
=
758 ResourceBundle::InitSharedInstanceWithLocale(locale
, NULL
);
759 if (loaded_locale
.empty() &&
760 !parsed_command_line().HasSwitch(switches::kNoErrorDialogs
)) {
761 ShowMissingLocaleMessageBox();
762 return chrome::RESULT_CODE_MISSING_DATA
;
764 CHECK(!loaded_locale
.empty()) << "Locale could not be found for " << locale
;
765 browser_process_
->SetApplicationLocale(loaded_locale
);
767 FilePath resources_pack_path
;
768 PathService::Get(chrome::FILE_RESOURCES_PACK
, &resources_pack_path
);
769 ResourceBundle::GetSharedInstance().AddDataPackFromPath(
770 resources_pack_path
, ui::SCALE_FACTOR_100P
);
771 #endif // defined(OS_MACOSX)
774 #if defined(TOOLKIT_GTK)
775 g_set_application_name(l10n_util::GetStringUTF8(IDS_PRODUCT_NAME
).c_str());
778 std::string try_chrome
=
779 parsed_command_line().GetSwitchValueASCII(switches::kTryChromeAgain
);
780 if (!try_chrome
.empty()) {
781 #if defined(OS_WIN) && !defined(USE_AURA)
782 // Setup.exe has determined that we need to run a retention experiment
783 // and has lauched chrome to show the experiment UI.
784 if (process_singleton_
->FoundOtherProcessWindow()) {
785 // It seems that we don't need to run the experiment since chrome
786 // in the same profile is already running.
787 VLOG(1) << "Retention experiment not required";
788 return TryChromeDialogView::NOT_NOW
;
791 base::StringToInt(try_chrome
, &try_chrome_int
);
792 TryChromeDialogView::Result answer
=
793 TryChromeDialogView::Show(try_chrome_int
, process_singleton_
.get());
794 if (answer
== TryChromeDialogView::NOT_NOW
)
795 return chrome::RESULT_CODE_NORMAL_EXIT_CANCEL
;
796 if (answer
== TryChromeDialogView::UNINSTALL_CHROME
)
797 return chrome::RESULT_CODE_NORMAL_EXIT_EXP2
;
798 // At this point the user is willing to try chrome again.
799 if (answer
== TryChromeDialogView::TRY_CHROME_AS_DEFAULT
) {
800 // Only set in the unattended case, the interactive case is Windows 8.
801 if (ShellIntegration::CanSetAsDefaultBrowser() ==
802 ShellIntegration::SET_DEFAULT_UNATTENDED
)
803 ShellIntegration::SetAsDefaultBrowser();
806 // We don't support retention experiments on Mac or Linux.
807 return content::RESULT_CODE_NORMAL_EXIT
;
808 #endif // defined(OS_WIN)
811 // On first run, we need to process the predictor preferences before the
812 // browser's profile_manager object is created, but after ResourceBundle
814 first_run_ui_bypass_
= false; // True to skip first run UI.
816 first_run_ui_bypass_
= !first_run::ProcessMasterPreferences(
817 user_data_dir_
, master_prefs_
.get());
818 AddFirstRunNewTabs(browser_creator_
.get(), master_prefs_
->new_tabs
);
820 // If we are running in App mode, we do not want to show the importer
822 if (!first_run_ui_bypass_
&&
823 (parsed_command_line().HasSwitch(switches::kApp
) ||
824 parsed_command_line().HasSwitch(switches::kAppId
) ||
825 parsed_command_line().HasSwitch(switches::kNoFirstRun
)))
826 first_run_ui_bypass_
= true;
828 // Create Sentinel if no-first-run argument is passed in.
829 if (parsed_command_line().HasSwitch(switches::kNoFirstRun
))
830 first_run::CreateSentinel();
833 // TODO(viettrungluu): why don't we run this earlier?
834 if (!parsed_command_line().HasSwitch(switches::kNoErrorDialogs
))
835 WarnAboutMinimumSystemRequirements();
837 #if defined(OS_LINUX) || defined(OS_OPENBSD) || defined(OS_MACOSX)
838 // Set the product channel for crash reports.
839 child_process_logging::SetChannel(
840 chrome::VersionInfo::GetVersionStringModifier());
843 InitializeNetworkOptions(parsed_command_line());
845 // Initialize tracking synchronizer system.
846 tracking_synchronizer_
= new chrome_browser_metrics::TrackingSynchronizer();
848 // Now that all preferences have been registered, set the install date
849 // for the uninstall metrics if this is our first run. This only actually
850 // gets used if the user has metrics reporting enabled at uninstall time.
852 local_state_
->GetInt64(prefs::kUninstallMetricsInstallDate
);
853 if (install_date
== 0) {
854 local_state_
->SetInt64(prefs::kUninstallMetricsInstallDate
,
855 base::Time::Now().ToTimeT());
858 #if defined(OS_MACOSX)
859 // Get the Keychain API to register for distributed notifications on the main
860 // thread, which has a proper CFRunloop, instead of later on the I/O thread,
861 // which doesn't. This ensures those notifications will get delivered
862 // properly. See issue 37766.
863 // (Note that the callback mask here is empty. I don't want to register for
864 // any callbacks, I just want to initialize the mechanism.)
865 SecKeychainAddCallback(&KeychainCallback
, 0, NULL
);
868 // Now the command line has been mutated based on about:flags, we can setup
869 // metrics and initialize field trials. The field trials are needed by
870 // IOThread's initialization which happens in BrowserProcess:PreCreateThreads.
871 SetupMetricsAndFieldTrials();
873 // ChromeOS needs ResourceBundle::InitSharedInstance to be called before this.
874 browser_process_
->PreCreateThreads();
876 return content::RESULT_CODE_NORMAL_EXIT
;
879 void ChromeBrowserMainParts::PreMainMessageLoopRun() {
880 result_code_
= PreMainMessageLoopRunImpl();
882 for (size_t i
= 0; i
< chrome_extra_parts_
.size(); ++i
)
883 chrome_extra_parts_
[i
]->PreMainMessageLoopRun();
886 // PreMainMessageLoopRun calls these extra stages in the following order:
887 // PreMainMessageLoopRunImpl()
888 // ... initial setup, including browser_process_ setup.
890 // ... additional setup, including CreateProfile()
892 // ... additional setup
894 // ... browser_creator_->Start (OR parameters().ui_task->Run())
895 // PostBrowserStart()
897 void ChromeBrowserMainParts::PreProfileInit() {
898 for (size_t i
= 0; i
< chrome_extra_parts_
.size(); ++i
)
899 chrome_extra_parts_
[i
]->PreProfileInit();
902 void ChromeBrowserMainParts::PostProfileInit() {
903 for (size_t i
= 0; i
< chrome_extra_parts_
.size(); ++i
)
904 chrome_extra_parts_
[i
]->PostProfileInit();
907 void ChromeBrowserMainParts::PreBrowserStart() {
908 for (size_t i
= 0; i
< chrome_extra_parts_
.size(); ++i
)
909 chrome_extra_parts_
[i
]->PreBrowserStart();
912 void ChromeBrowserMainParts::PostBrowserStart() {
913 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kVisitURLs
))
916 for (size_t i
= 0; i
< chrome_extra_parts_
.size(); ++i
)
917 chrome_extra_parts_
[i
]->PostBrowserStart();
918 // Allow ProcessSingleton to process messages.
919 process_singleton_
->Unlock();
922 void ChromeBrowserMainParts::RunPageCycler() {
923 CommandLine
* command_line
= CommandLine::ForCurrentProcess();
924 Browser
* browser
= browser::FindBrowserWithProfile(profile_
);
926 PageCycler
* page_cycler
= NULL
;
927 FilePath input_file
=
928 command_line
->GetSwitchValuePath(switches::kVisitURLs
);
929 page_cycler
= new PageCycler(browser
, input_file
);
930 page_cycler
->set_errors_file(
931 input_file
.AddExtension(FILE_PATH_LITERAL(".errors")));
932 if (command_line
->HasSwitch(switches::kRecordStats
)) {
933 page_cycler
->set_stats_file(
934 command_line
->GetSwitchValuePath(switches::kRecordStats
));
939 void ChromeBrowserMainParts::SetupPlatformFieldTrials() {
940 // Base class implementation of this does nothing.
943 int ChromeBrowserMainParts::PreMainMessageLoopRunImpl() {
944 // Now that the file thread has been started, start recording.
945 StartMetricsRecording();
947 // Create watchdog thread after creating all other threads because it will
948 // watch the other threads and they must be running.
949 browser_process_
->watchdog_thread();
951 // Do any initializating in the browser process that requires all threads
953 browser_process_
->PreMainMessageLoopRun();
955 // Record last shutdown time into a histogram.
956 browser_shutdown::ReadLastShutdownInfo();
959 // On Windows, we use our startup as an opportunity to do upgrade/uninstall
960 // tasks. Those care whether the browser is already running. On Linux/Mac,
961 // upgrade/uninstall happen separately.
962 bool already_running
= browser_util::IsBrowserAlreadyRunning();
964 // If the command line specifies 'uninstall' then we need to work here
965 // unless we detect another chrome browser running.
966 if (parsed_command_line().HasSwitch(switches::kUninstall
)) {
967 return DoUninstallTasks(already_running
);
970 if (parsed_command_line().HasSwitch(switches::kHideIcons
) ||
971 parsed_command_line().HasSwitch(switches::kShowIcons
)) {
972 return ChromeBrowserMainPartsWin::HandleIconsCommands(
973 parsed_command_line_
);
977 if (parsed_command_line().HasSwitch(switches::kMakeDefaultBrowser
)) {
978 return ShellIntegration::SetAsDefaultBrowser() ?
979 static_cast<int>(content::RESULT_CODE_NORMAL_EXIT
) :
980 static_cast<int>(chrome::RESULT_CODE_SHELL_INTEGRATION_FAILED
);
983 // If the command line specifies --pack-extension, attempt the pack extension
984 // startup action and exit.
985 if (parsed_command_line().HasSwitch(switches::kPackExtension
)) {
986 ExtensionsStartupUtil extension_startup_util
;
987 if (extension_startup_util
.PackExtension(parsed_command_line()))
988 return content::RESULT_CODE_NORMAL_EXIT
;
989 return chrome::RESULT_CODE_PACK_EXTENSION_ERROR
;
992 bool pass_command_line
= true;
994 #if !defined(OS_MACOSX)
995 // In environments other than Mac OS X we support import of settings
996 // from other browsers. In case this process is a short-lived "import"
997 // process that another browser runs just to import the settings, we
998 // don't want to be checking for another browser process, by design.
999 pass_command_line
= !HasImportSwitch(parsed_command_line());
1002 // If we're being launched just to check the connector policy, we are
1003 // short-lived and don't want to be passing that switch off.
1004 pass_command_line
= pass_command_line
&& !parsed_command_line().HasSwitch(
1005 switches::kCheckCloudPrintConnectorPolicy
);
1007 if (pass_command_line
) {
1008 // When another process is running, use that process instead of starting a
1009 // new one. NotifyOtherProcess will currently give the other process up to
1010 // 20 seconds to respond. Note that this needs to be done before we attempt
1011 // to read the profile.
1012 notify_result_
= process_singleton_
->NotifyOtherProcessOrCreate(
1013 base::Bind(&ProcessSingletonNotificationCallback
));
1014 switch (notify_result_
) {
1015 case ProcessSingleton::PROCESS_NONE
:
1016 // No process already running, fall through to starting a new one.
1019 case ProcessSingleton::PROCESS_NOTIFIED
:
1020 #if defined(OS_POSIX) && !defined(OS_MACOSX)
1021 printf("%s\n", base::SysWideToNativeMB(UTF16ToWide(
1022 l10n_util::GetStringUTF16(IDS_USED_EXISTING_BROWSER
))).c_str());
1024 return chrome::RESULT_CODE_NORMAL_EXIT_PROCESS_NOTIFIED
;
1026 case ProcessSingleton::PROFILE_IN_USE
:
1027 return chrome::RESULT_CODE_PROFILE_IN_USE
;
1029 case ProcessSingleton::LOCK_ERROR
:
1030 LOG(ERROR
) << "Failed to create a ProcessSingleton for your profile "
1031 "directory. This means that running multiple instances "
1032 "would start multiple browser processes rather than "
1033 "opening a new window in the existing process. Aborting "
1034 "now to avoid profile corruption.";
1035 return chrome::RESULT_CODE_PROFILE_IN_USE
;
1042 #if defined(USE_X11)
1043 SetBrowserX11ErrorHandlers();
1046 // Desktop construction occurs here, (required before profile creation).
1049 // Profile creation ----------------------------------------------------------
1051 if (is_first_run_
) {
1052 // Warn the ProfileManager that an import process will run, possibly
1053 // locking the WebDataService directory of the next Profile created.
1054 browser_process_
->profile_manager()->SetWillImport();
1057 profile_
= CreateProfile(parameters(), user_data_dir_
, parsed_command_line());
1059 return content::RESULT_CODE_NORMAL_EXIT
;
1061 // Autoload any profiles which are running background apps.
1062 // TODO(rlp): Do this on a separate thread. See http://crbug.com/99075.
1063 browser_process_
->profile_manager()->AutoloadProfiles();
1065 // Post-profile init ---------------------------------------------------------
1067 #if !defined(OS_MACOSX)
1068 // Importing other browser settings is done in a browser-like process
1069 // that exits when this task has finished.
1070 // TODO(port): Port the Mac's IPC-based implementation to other platforms to
1071 // replace this implementation. http://crbug.com/22142
1072 if (HasImportSwitch(parsed_command_line())) {
1073 return first_run::ImportNow(profile_
, parsed_command_line());
1078 // Do the tasks if chrome has been upgraded while it was last running.
1079 if (!already_running
&& upgrade_util::DoUpgradeTasks(parsed_command_line()))
1080 return content::RESULT_CODE_NORMAL_EXIT
;
1082 // Check if there is any machine level Chrome installed on the current
1083 // machine. If yes and the current Chrome process is user level, we do not
1084 // allow the user level Chrome to run. So we notify the user and uninstall
1085 // user level Chrome.
1086 // Note this check should only happen here, after all the checks above
1087 // (uninstall, resource bundle initialization, other chrome browser
1089 // Do not allow this to occur for Chrome Frame user-to-system handoffs.
1090 if (!parsed_command_line().HasSwitch(switches::kChromeFrame
) &&
1091 ChromeBrowserMainPartsWin::CheckMachineLevelInstall()) {
1092 return chrome::RESULT_CODE_MACHINE_LEVEL_INSTALL_EXISTS
;
1096 // Create the TranslateManager singleton.
1097 translate_manager_
= TranslateManager::GetInstance();
1098 DCHECK(translate_manager_
!= NULL
);
1100 // Initialize Managed Mode.
1101 ManagedMode::Init(profile_
);
1103 // TODO(stevenjb): Move WIN and MACOSX specific code to appropriate Parts.
1104 // (requires supporting early exit).
1107 // Show the First Run UI if this is the first time Chrome has been run on
1108 // this computer, or we're being compelled to do so by a command line flag.
1109 // Note that this be done _after_ the PrefService is initialized and all
1110 // preferences are registered, since some of the code that the importer
1111 // touches reads preferences.
1112 if (is_first_run_
) {
1113 if (!first_run_ui_bypass_
) {
1114 first_run::AutoImport(profile_
,
1115 master_prefs_
->homepage_defined
,
1116 master_prefs_
->do_import_items
,
1117 master_prefs_
->dont_import_items
,
1118 master_prefs_
->make_chrome_default
,
1119 process_singleton_
.get());
1120 #if defined(OS_POSIX) && !defined(OS_CHROMEOS)
1121 // On Windows, the download is tagged with enable/disable stats so there
1122 // is no need for this code.
1124 // If stats reporting was turned on by the first run dialog then toggle
1126 if (GoogleUpdateSettings::GetCollectStatsConsent())
1127 local_state_
->SetBoolean(prefs::kMetricsReportingEnabled
, true);
1128 #endif // OS_POSIX && !OS_CHROMEOS
1129 } // if (!first_run_ui_bypass_)
1131 chrome::SetNewHomePagePrefs(profile_
->GetPrefs());
1132 browser_process_
->profile_manager()->OnImportFinished(profile_
);
1134 if (!master_prefs_
->suppress_first_run_default_browser_prompt
)
1135 chrome::ShowFirstRunDefaultBrowserPrompt(profile_
);
1137 browser_creator_
->set_is_default_browser_dialog_suppressed(true);
1138 } // if (is_first_run_)
1141 // Sets things up so that if we crash from this point on, a dialog will
1142 // popup asking the user to restart chrome. It is done this late to avoid
1143 // testing against a bunch of special cases that are taken care early on.
1144 ChromeBrowserMainPartsWin::PrepareRestartOnCrashEnviroment(
1145 parsed_command_line());
1147 // Registers Chrome with the Windows Restart Manager, which will restore the
1148 // Chrome session when the computer is restarted after a system update.
1149 // This could be run as late as WM_QUERYENDSESSION for system update reboots,
1150 // but should run on startup if extended to handle crashes/hangs/patches.
1151 // Also, better to run once here than once for each HWND's WM_QUERYENDSESSION.
1152 if (base::win::GetVersion() >= base::win::VERSION_VISTA
) {
1153 ChromeBrowserMainPartsWin::RegisterApplicationRestart(
1154 parsed_command_line());
1157 // Verify that the profile is not on a network share and if so prepare to show
1158 // notification to the user.
1159 if (NetworkProfileBubble::ShouldCheckNetworkProfile(profile_
)) {
1160 content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE
,
1161 base::Bind(&NetworkProfileBubble::CheckNetworkProfile
, profile_
));
1165 #if defined(ENABLE_RLZ)
1166 // Init the RLZ library. This just binds the dll and schedules a task on the
1167 // file thread to be run sometime later. If this is the first run we record
1168 // the installation event.
1169 bool google_search_default
= false;
1170 TemplateURLService
* template_url_service
=
1171 TemplateURLServiceFactory::GetForProfile(profile_
);
1172 if (template_url_service
) {
1173 const TemplateURL
* url_template
=
1174 template_url_service
->GetDefaultSearchProvider();
1175 google_search_default
=
1176 url_template
&& url_template
->url_ref().HasGoogleBaseURLs();
1179 PrefService
* pref_service
= profile_
->GetPrefs();
1180 bool google_search_homepage
= pref_service
&&
1181 google_util::IsGoogleHomePageUrl(
1182 pref_service
->GetString(prefs::kHomePage
));
1184 RLZTracker::InitRlzDelayed(is_first_run_
, master_prefs_
->ping_delay
,
1185 google_search_default
, google_search_homepage
);
1187 // Prime the RLZ cache for the home page access point so that its avaiable
1188 // for the startup page if needed (i.e., when the startup page is set to
1190 RLZTracker::GetAccessPointRlz(rlz_lib::CHROME_HOME_PAGE
, NULL
);
1191 #endif // defined(ENABLE_RLZ)
1193 // Configure modules that need access to resources.
1194 net::NetModule::SetResourceProvider(chrome_common_net::NetResourceProvider
);
1196 // In unittest mode, this will do nothing. In normal mode, this will create
1197 // the global IntranetRedirectDetector instance, which will promptly go to
1198 // sleep for seven seconds (to avoid slowing startup), and wake up afterwards
1199 // to see if it should do anything else.
1201 // A simpler way of doing all this would be to have some function which could
1202 // give the time elapsed since startup, and simply have this object check that
1203 // when asked to initialize itself, but this doesn't seem to exist.
1205 // This can't be created in the BrowserProcessImpl constructor because it
1206 // needs to read prefs that get set after that runs.
1207 browser_process_
->intranet_redirect_detector();
1208 GoogleSearchCounter::RegisterForNotifications();
1210 // Disable SDCH filtering if switches::kEnableSdch is 0.
1211 int sdch_enabled
= 1;
1212 if (parsed_command_line().HasSwitch(switches::kEnableSdch
)) {
1213 base::StringToInt(parsed_command_line().GetSwitchValueASCII(
1214 switches::kEnableSdch
), &sdch_enabled
);
1216 net::SdchManager::EnableSdchSupport(false);
1219 // Perform A/B test to measure global impact of SDCH support.
1220 // Set up a field trial to see what disabling SDCH does to latency of page
1222 base::FieldTrial::Probability kSDCH_DIVISOR
= 1000;
1223 base::FieldTrial::Probability kSDCH_DISABLE_PROBABILITY
= 1; // 0.1% prob.
1224 // After March 31, 2012 builds, it will always be in default group.
1225 int sdch_enabled_group
= -1;
1226 scoped_refptr
<base::FieldTrial
> sdch_trial(
1227 base::FieldTrialList::FactoryGetFieldTrial(
1228 "GlobalSdch", kSDCH_DIVISOR
, "global_enable_sdch", 2012, 3, 31,
1229 &sdch_enabled_group
));
1231 sdch_trial
->AppendGroup("global_disable_sdch",
1232 kSDCH_DISABLE_PROBABILITY
);
1233 if (sdch_enabled_group
!= sdch_trial
->group())
1234 net::SdchManager::EnableSdchSupport(false);
1237 if (parsed_command_line().HasSwitch(switches::kEnableWatchdog
))
1238 InstallJankometer(parsed_command_line());
1240 #if defined(OS_WIN) && !defined(GOOGLE_CHROME_BUILD)
1241 if (parsed_command_line().HasSwitch(switches::kDebugPrint
)) {
1243 parsed_command_line().GetSwitchValuePath(switches::kDebugPrint
);
1244 printing::PrintedDocument::set_debug_dump_path(path
);
1248 HandleTestParameters(parsed_command_line());
1249 RecordBreakpadStatusUMA(browser_process_
->metrics_service());
1250 about_flags::RecordUMAStatistics(local_state_
);
1251 LanguageUsageMetrics::RecordAcceptLanguages(
1252 profile_
->GetPrefs()->GetString(prefs::kAcceptLanguages
));
1253 LanguageUsageMetrics::RecordApplicationLanguage(
1254 browser_process_
->GetApplicationLocale());
1256 // The extension service may be available at this point. If the command line
1257 // specifies --uninstall-extension, attempt the uninstall extension startup
1259 if (parsed_command_line().HasSwitch(switches::kUninstallExtension
)) {
1260 ExtensionsStartupUtil ext_startup_util
;
1261 if (ext_startup_util
.UninstallExtension(parsed_command_line(), profile_
))
1262 return content::RESULT_CODE_NORMAL_EXIT
;
1263 return chrome::RESULT_CODE_UNINSTALL_EXTENSION_ERROR
;
1266 // Start watching for hangs during startup. We disarm this hang detector when
1267 // ThreadWatcher takes over or when browser is shutdown or when
1268 // startup_watcher_ is deleted.
1269 startup_watcher_
->Arm(base::TimeDelta::FromSeconds(300));
1271 // Start watching for a hang.
1272 MetricsService::LogNeedForCleanShutdown();
1275 // We check this here because if the profile is OTR (chromeos possibility)
1276 // it won't still be accessible after browser is destroyed.
1277 record_search_engine_
= is_first_run_
&& !profile_
->IsOffTheRecord();
1280 // Create the instance of the cloud print proxy service so that it can launch
1281 // the service process if needed. This is needed because the service process
1282 // might have shutdown because an update was available.
1283 // TODO(torne): this should maybe be done with
1284 // ProfileKeyedServiceFactory::ServiceIsCreatedWithProfile() instead?
1285 #if !defined(OS_ANDROID)
1286 CloudPrintProxyServiceFactory::GetForProfile(profile_
);
1289 // Load GPU Blacklist.
1290 InitializeGpuDataManager(parsed_command_line());
1292 // Start watching all browser threads for responsiveness.
1293 ThreadWatcherList::StartWatchingAll(parsed_command_line());
1295 #if !defined(DISABLE_NACL)
1296 if (parsed_command_line().HasSwitch(switches::kPnaclDir
)) {
1297 PathService::Override(chrome::DIR_PNACL_BASE
,
1298 parsed_command_line().GetSwitchValuePath(
1299 switches::kPnaclDir
));
1301 NaClProcessHost::EarlyStartup();
1306 // Instantiate the notification UI manager, as this triggers a perf timer
1307 // used to measure startup time. TODO(stevenjb): Figure out what is actually
1308 // triggering the timer and call that explicitly in the approprate place.
1309 // http://crbug.com/105065.
1310 browser_process_
->notification_ui_manager();
1312 // Most general initialization is behind us, but opening a
1313 // tab and/or session restore and such is still to be done.
1314 base::TimeTicks browser_open_start
= base::TimeTicks::Now();
1316 // We are in regular browser boot sequence. Open initial tabs and enter the
1317 // main message loop.
1319 #if defined(OS_CHROMEOS)
1320 // On ChromeOS multiple profiles doesn't apply, and will break if we load
1321 // them this early as the cryptohome hasn't yet been mounted (which happens
1322 // only once we log in.
1323 std::vector
<Profile
*> last_opened_profiles
;
1325 std::vector
<Profile
*> last_opened_profiles
=
1326 g_browser_process
->profile_manager()->GetLastOpenedProfiles();
1328 if (browser_creator_
->Start(parsed_command_line(), FilePath(),
1329 profile_
, last_opened_profiles
, &result_code
)) {
1330 #if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS))
1331 // Initialize autoupdate timer. Timer callback costs basically nothing
1332 // when browser is not in persistent mode, so it's OK to let it ride on
1333 // the main thread. This needs to be done here because we don't want
1334 // to start the timer when Chrome is run inside a test harness.
1335 browser_process_
->StartAutoupdateTimer();
1338 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
1339 // On Linux, the running exe will be updated if an upgrade becomes
1340 // available while the browser is running. We need to save the last
1341 // modified time of the exe, so we can compare to determine if there is
1342 // an upgrade while the browser is kept alive by a persistent extension.
1343 upgrade_util::SaveLastModifiedTimeOfExe();
1346 // Record now as the last successful chrome start.
1347 GoogleUpdateSettings::SetLastRunTime();
1349 #if defined(OS_MACOSX)
1350 // Call Recycle() here as late as possible, before going into the loop
1351 // because Start() will add things to it while creating the main window.
1352 if (parameters().autorelease_pool
)
1353 parameters().autorelease_pool
->Recycle();
1356 RecordPreReadExperimentTime("Startup.BrowserOpenTabs",
1357 base::TimeTicks::Now() - browser_open_start
);
1359 // TODO(mad): Move this call in a proper place on CrOS.
1360 // http://crosbug.com/17687
1361 #if !defined(OS_CHROMEOS)
1362 // If we're running tests (ui_task is non-null), then we don't want to
1363 // call FetchLanguageListFromTranslateServer or
1364 // StartRepeatedVariationsSeedFetch.
1365 if (parameters().ui_task
== NULL
) {
1366 // Request new variations seed information from server.
1367 browser_process_
->variations_service()->
1368 StartRepeatedVariationsSeedFetch();
1370 if (translate_manager_
!= NULL
) {
1371 translate_manager_
->FetchLanguageListFromTranslateServer(
1372 profile_
->GetPrefs());
1377 run_message_loop_
= true;
1379 run_message_loop_
= false;
1381 browser_creator_
.reset();
1385 if (parameters().ui_task
) {
1386 parameters().ui_task
->Run();
1387 delete parameters().ui_task
;
1388 run_message_loop_
= false;
1391 return result_code_
;
1394 bool ChromeBrowserMainParts::MainMessageLoopRun(int* result_code
) {
1395 // Set the result code set in PreMainMessageLoopRun or set above.
1396 *result_code
= result_code_
;
1397 if (!run_message_loop_
)
1398 return true; // Don't run the default message loop.
1400 // This should be invoked as close to the start of the browser's
1401 // UI thread message loop as possible to get a stable measurement
1403 RecordBrowserStartupTime();
1404 DCHECK_EQ(MessageLoop::TYPE_UI
, MessageLoop::current()->type());
1405 #if !defined(USE_AURA) && defined(TOOLKIT_VIEWS)
1406 views::AcceleratorHandler accelerator_handler
;
1407 base::RunLoop
run_loop(&accelerator_handler
);
1409 base::RunLoop run_loop
;
1416 void ChromeBrowserMainParts::PostMainMessageLoopRun() {
1417 // Start watching for jank during shutdown. It gets disarmed when
1418 // |shutdown_watcher_| object is destructed.
1419 shutdown_watcher_
->Arm(base::TimeDelta::FromSeconds(300));
1421 // Disarm the startup hang detector time bomb if it is still Arm'ed.
1422 startup_watcher_
->Disarm();
1424 for (size_t i
= 0; i
< chrome_extra_parts_
.size(); ++i
)
1425 chrome_extra_parts_
[i
]->PostMainMessageLoopRun();
1428 // Log the search engine chosen on first run. Do this at shutdown, after any
1429 // changes are made from the first run bubble link, etc.
1430 if (record_search_engine_
) {
1431 TemplateURLService
* url_service
=
1432 TemplateURLServiceFactory::GetForProfile(profile_
);
1433 const TemplateURL
* default_search_engine
=
1434 url_service
->GetDefaultSearchProvider();
1435 // The default engine can be NULL if the administrator has disabled
1437 SearchEngineType search_engine_type
=
1438 TemplateURLPrepopulateData::GetEngineType(default_search_engine
?
1439 default_search_engine
->url() : std::string());
1440 // Record the search engine chosen.
1441 UMA_HISTOGRAM_ENUMERATION("Chrome.SearchSelectExempt", search_engine_type
,
1446 // Some tests don't set parameters.ui_task, so they started translate
1447 // language fetch that was never completed so we need to cleanup here
1448 // otherwise it will be done by the destructor in a wrong thread.
1449 if (parameters().ui_task
== NULL
&& translate_manager_
!= NULL
)
1450 translate_manager_
->CleanupPendingUlrFetcher();
1452 if (notify_result_
== ProcessSingleton::PROCESS_NONE
)
1453 process_singleton_
->Cleanup();
1455 // Stop all tasks that might run on WatchDogThread.
1456 ThreadWatcherList::StopWatchingAll();
1458 browser_process_
->metrics_service()->Stop();
1460 restart_last_session_
= browser_shutdown::ShutdownPreThreadsStop();
1461 browser_process_
->StartTearDown();
1464 void ChromeBrowserMainParts::PostDestroyThreads() {
1465 browser_process_
->PostDestroyThreads();
1466 // browser_shutdown takes care of deleting browser_process, so we need to
1468 ignore_result(browser_process_
.release());
1469 browser_shutdown::ShutdownPostThreadsStop(restart_last_session_
);
1470 master_prefs_
.reset();
1471 process_singleton_
.reset();
1473 // We need to do this check as late as possible, but due to modularity, this
1474 // may be the last point in Chrome. This would be more effective if done at
1475 // a higher level on the stack, so that it is impossible for an early return
1476 // to bypass this code. Perhaps we need a *final* hook that is called on all
1477 // paths from content/browser/browser_main.
1478 CHECK(MetricsService::UmaMetricsProperlyShutdown());
1483 void ChromeBrowserMainParts::AddParts(ChromeBrowserMainExtraParts
* parts
) {
1484 chrome_extra_parts_
.push_back(parts
);
1487 // Misc ------------------------------------------------------------------------
1489 void RecordBrowserStartupTime() {
1490 // CurrentProcessInfo::CreationTime() is currently only implemented on Mac and
1492 #if defined(OS_MACOSX) || defined(OS_WIN)
1493 const base::Time
*process_creation_time
=
1494 base::CurrentProcessInfo::CreationTime();
1496 if (process_creation_time
)
1497 RecordPreReadExperimentTime("Startup.BrowserMessageLoopStartTime",
1498 base::Time::Now() - *process_creation_time
);
1499 #endif // OS_MACOSX || OS_WIN
1502 // This code is specific to the Windows-only PreReadExperiment field-trial.
1503 void RecordPreReadExperimentTime(const char* name
, base::TimeDelta time
) {
1504 DCHECK(name
!= NULL
);
1506 // This gets called with different histogram names, so we don't want to use
1507 // the UMA_HISTOGRAM_CUSTOM_TIMES macro--it uses a static variable, and the
1509 AddPreReadHistogramTime(name
, time
);
1512 #if defined(GOOGLE_CHROME_BUILD)
1513 // The pre-read experiment is Windows and Google Chrome specific.
1514 scoped_ptr
<base::Environment
> env(base::Environment::Create());
1516 // Only record the sub-histogram result if the experiment is running
1517 // (environment variable is set, and valid).
1518 std::string pre_read_percentage
;
1519 if (env
->GetVar(chrome::kPreReadEnvironmentVariable
, &pre_read_percentage
)) {
1520 std::string
uma_name(name
);
1522 // We want XP to record a separate histogram, as the loader on XP
1523 // is very different from the Vista and Win7 loaders.
1524 if (base::win::GetVersion() <= base::win::VERSION_XP
)
1527 uma_name
+= "_PreRead_";
1528 uma_name
+= pre_read_percentage
;
1529 AddPreReadHistogramTime(uma_name
.c_str(), time
);