Inactive user toast. Set chrome as default.
[chromium-blink-merge.git] / chrome / browser / chrome_browser_main.cc
blob84a6a510644adb096528bc9aec9626c23a70a138
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/chrome_browser_main.h"
7 #include <algorithm>
8 #include <string>
9 #include <vector>
11 #include "base/at_exit.h"
12 #include "base/bind.h"
13 #include "base/command_line.h"
14 #include "base/debug/trace_event.h"
15 #include "base/file_path.h"
16 #include "base/file_util.h"
17 #include "base/metrics/field_trial.h"
18 #include "base/metrics/histogram.h"
19 #include "base/path_service.h"
20 #include "base/process_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"
124 #endif
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"
130 #endif
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.
137 #if defined(OS_WIN)
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"
160 #endif
162 #if defined(ENABLE_RLZ)
163 #include "chrome/browser/rlz/rlz.h"
164 #endif
166 #if defined(TOOLKIT_VIEWS)
167 #include "ui/views/focus/accelerator_handler.h"
168 #endif
170 #if defined(USE_X11)
171 #include "chrome/browser/chrome_browser_main_x11.h"
172 #endif
174 using content::BrowserThread;
176 namespace {
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)) {
183 DCHECK(false);
186 // This parameter causes a null pointer crash (crash reporter trigger).
187 if (command_line.HasSwitch(switches::kBrowserCrashTest)) {
188 int* bad_pointer = NULL;
189 *bad_pointer = 0;
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) {
197 if (it->is_valid())
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)) {
223 int value;
224 base::StringToInt(
225 parsed_command_line.GetSwitchValueASCII(
226 switches::kMaxSpdySessionsPerDomain),
227 &value);
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)) {
240 int value;
241 base::StringToInt(
242 parsed_command_line.GetSwitchValueASCII(
243 switches::kTestingFixedHttpPort),
244 &value);
245 net::HttpStreamFactory::set_testing_fixed_http_port(value);
248 if (parsed_command_line.HasSwitch(switches::kTestingFixedHttpsPort)) {
249 int value;
250 base::StringToInt(
251 parsed_command_line.GetSwitchValueASCII(
252 switches::kTestingFixedHttpsPort),
253 &value);
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,
260 bool is_first_run) {
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();
268 DCHECK(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
275 // are registered.
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,
280 std::string());
281 #endif // defined(OS_CHROMEOS)
282 #if !defined(OS_CHROMEOS)
283 local_state->RegisterBooleanPref(prefs::kMetricsReportingEnabled,
284 GoogleUpdateSettings::GetCollectStatsConsent());
285 #endif // !defined(OS_CHROMEOS)
287 if (is_first_run) {
288 #if defined(OS_WIN)
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(),
316 NULL, false));
317 parent_local_state->RegisterStringPref(prefs::kApplicationLocale,
318 std::string());
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);
335 #endif
337 return local_state;
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) {
346 Profile* profile;
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
352 // profile.
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(
361 user_data_dir);
362 #else
363 profile = g_browser_process->profile_manager()->GetLastUsedProfile(
364 user_data_dir);
365 #endif
366 if (profile)
367 return profile;
369 #if defined(OS_WIN)
370 #if defined(USE_AURA)
371 // TODO(beng):
372 NOTIMPLEMENTED();
373 #else
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
376 // with the new dir.
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,
387 new_user_data_dir);
388 base::LaunchProcess(new_command_line, base::LaunchOptions(), NULL);
390 #endif
391 #else
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.";
396 #endif
398 return NULL;
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)) {
407 return;
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);
416 DCHECK(succeed);
417 gpu_blacklist->UpdateGpuDataManager();
420 #if defined(OS_MACOSX)
421 OSStatus KeychainCallback(SecKeychainEvent keychain_event,
422 SecKeychainCallbackInfo* info, void* context) {
423 return noErr;
425 #endif
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())
445 return false;
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
453 // directory switch.
454 DCHECK(!command_line.HasSwitch(switches::kProfileDirectory));
456 Profile* profile = ProfileManager::GetLastUsedProfile();
457 if (!profile) {
458 // We should never be called before the profile has been created.
459 NOTREACHED();
460 return true;
463 ExtensionsStartupUtil ext_startup_util;
464 ext_startup_util.UninstallExtension(command_line, profile);
465 return true;
468 StartupBrowserCreator::ProcessCommandLineAlreadyRunning(
469 command_line, current_directory);
470 return true;
473 bool HasImportSwitch(const CommandLine& command_line) {
474 return (command_line.HasSwitch(switches::kImport) ||
475 command_line.HasSwitch(switches::kImportFromFile));
478 } // namespace
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 ------------------------------------------------------------
490 // static
491 bool ChromeBrowserMainParts::disable_enforcing_cookie_policies_for_tests_ =
492 false;
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),
504 profile_(NULL),
505 run_message_loop_(true),
506 notify_result_(ProcessSingleton::PROCESS_NONE),
507 is_first_run_(false),
508 first_run_ui_bypass_(false),
509 local_state_(NULL),
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).
533 #if defined(OS_WIN)
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
541 // randomization.
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.
550 #ifndef NDEBUG
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 <<
557 " list specified.";
559 #endif // NDEBUG
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();
586 return;
589 if (IsMetricsReportingEnabled())
590 metrics->Start();
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;
598 #ifndef NDEBUG
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))
602 return false;
603 #endif // #ifndef NDEBUG
605 #if defined(GOOGLE_CHROME_BUILD)
606 #if defined(OS_CHROMEOS)
607 chromeos::CrosSettings::Get()->GetBoolean(chromeos::kStatsReportingPref,
608 &enabled);
609 #else
610 enabled = local_state_->GetBoolean(prefs::kMetricsReportingEnabled);
611 #endif // #if defined(OS_CHROMEOS)
612 #endif // defined(GOOGLE_CHROME_BUILD)
613 return enabled;
616 // -----------------------------------------------------------------------------
617 // TODO(viettrungluu): move more/rest of BrowserMain() into BrowserMainParts.
619 #if defined(OS_WIN)
620 #define DLLEXPORT __declspec(dllexport)
622 // We use extern C for the prototype DLLEXPORT to avoid C++ name mangling.
623 extern "C" {
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();
634 #endif
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());
675 return result_code_;
678 int ChromeBrowserMainParts::PreCreateThreadsImpl() {
679 run_message_loop_ = false;
680 #if defined(OS_WIN)
681 PathService::Get(chrome::DIR_USER_DATA, &user_data_dir_);
682 #else
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!";
690 #endif
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);
697 is_first_run_ =
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.
705 std::string flag =
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");
746 } else {
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());
752 #else
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());
776 #endif
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;
790 int try_chrome_int;
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();
805 #else
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
813 // is initialized.
814 first_run_ui_bypass_ = false; // True to skip first run UI.
815 if (is_first_run_) {
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
821 // (first run) UI.
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());
841 #endif
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.
851 int64 install_date =
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);
866 #endif
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.
889 // PreProfileInit()
890 // ... additional setup, including CreateProfile()
891 // PostProfileInit()
892 // ... additional setup
893 // PreBrowserStart()
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))
914 RunPageCycler();
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_);
925 DCHECK(browser);
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));
936 page_cycler->Run();
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
952 // running.
953 browser_process_->PreMainMessageLoopRun();
955 // Record last shutdown time into a histogram.
956 browser_shutdown::ReadLastShutdownInfo();
958 #if defined(OS_WIN)
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_);
975 #endif
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());
1000 #endif
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.
1017 break;
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());
1023 #endif
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;
1037 default:
1038 NOTREACHED();
1042 #if defined(USE_X11)
1043 SetBrowserX11ErrorHandlers();
1044 #endif
1046 // Desktop construction occurs here, (required before profile creation).
1047 PreProfileInit();
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());
1058 if (!profile_)
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());
1075 #endif
1077 #if defined(OS_WIN)
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
1088 // processes etc).
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;
1094 #endif
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).
1105 PostProfileInit();
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
1125 // the pref.
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_);
1136 else
1137 browser_creator_->set_is_default_browser_dialog_suppressed(true);
1138 } // if (is_first_run_)
1140 #if defined(OS_WIN)
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_));
1163 #endif // OS_WIN
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
1189 // the home page).
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);
1215 if (!sdch_enabled)
1216 net::SdchManager::EnableSdchSupport(false);
1218 if (sdch_enabled) {
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
1221 // layout globally.
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)) {
1242 FilePath path =
1243 parsed_command_line().GetSwitchValuePath(switches::kDebugPrint);
1244 printing::PrintedDocument::set_debug_dump_path(path);
1246 #endif
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
1258 // action.
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();
1274 #if defined(OS_WIN)
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();
1278 #endif
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_);
1287 #endif
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();
1302 #endif
1304 PreBrowserStart();
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.
1318 int result_code;
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;
1324 #else
1325 std::vector<Profile*> last_opened_profiles =
1326 g_browser_process->profile_manager()->GetLastOpenedProfiles();
1327 #endif
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();
1336 #endif
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();
1344 #endif
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();
1354 #endif
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());
1375 #endif
1377 run_message_loop_ = true;
1378 } else {
1379 run_message_loop_ = false;
1381 browser_creator_.reset();
1383 PostBrowserStart();
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
1402 // across versions.
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);
1408 #else
1409 base::RunLoop run_loop;
1410 #endif
1411 run_loop.Run();
1413 return true;
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();
1427 #if defined(OS_WIN)
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
1436 // default search.
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,
1442 SEARCH_ENGINE_MAX);
1444 #endif
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
1467 // release it.
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());
1481 // Public members:
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
1491 // Windows.
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
1508 // first call wins.
1509 AddPreReadHistogramTime(name, time);
1511 #if defined(OS_WIN)
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)
1525 uma_name += "_XP";
1527 uma_name += "_PreRead_";
1528 uma_name += pre_read_percentage;
1529 AddPreReadHistogramTime(uma_name.c_str(), time);
1531 #endif
1532 #endif