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.
4
5#include "chrome/browser/chrome_browser_main.h"
6
7#include <set>
8#include <string>
9#include <vector>
10
11#include "base/at_exit.h"
12#include "base/bind.h"
13#include "base/command_line.h"
14#include "base/debug/crash_logging.h"
15#include "base/debug/debugger.h"
16#include "base/debug/trace_event.h"
17#include "base/files/file_path.h"
18#include "base/files/file_util.h"
19#include "base/metrics/field_trial.h"
20#include "base/metrics/histogram.h"
21#include "base/path_service.h"
22#include "base/prefs/json_pref_store.h"
23#include "base/prefs/pref_registry_simple.h"
24#include "base/prefs/pref_service.h"
25#include "base/prefs/pref_value_store.h"
26#include "base/prefs/scoped_user_pref_update.h"
27#include "base/process/process_info.h"
28#include "base/run_loop.h"
29#include "base/strings/string_number_conversions.h"
30#include "base/strings/string_piece.h"
31#include "base/strings/string_split.h"
32#include "base/strings/sys_string_conversions.h"
33#include "base/strings/utf_string_conversions.h"
34#include "base/sys_info.h"
35#include "base/threading/platform_thread.h"
36#include "base/time/time.h"
37#include "base/values.h"
38#include "build/build_config.h"
39#include "chrome/browser/about_flags.h"
40#include "chrome/browser/browser_process.h"
41#include "chrome/browser/browser_process_impl.h"
42#include "chrome/browser/browser_process_platform_part.h"
43#include "chrome/browser/browser_shutdown.h"
44#include "chrome/browser/chrome_browser_main_extra_parts.h"
45#include "chrome/browser/component_updater/cld_component_installer.h"
46#include "chrome/browser/component_updater/ev_whitelist_component_installer.h"
47#include "chrome/browser/component_updater/flash_component_installer.h"
48#include "chrome/browser/component_updater/recovery_component_installer.h"
49#include "chrome/browser/component_updater/swiftshader_component_installer.h"
50#include "chrome/browser/component_updater/widevine_cdm_component_installer.h"
51#include "chrome/browser/defaults.h"
52#include "chrome/browser/first_run/first_run.h"
53#include "chrome/browser/first_run/upgrade_util.h"
54#include "chrome/browser/google/google_search_counter.h"
55#include "chrome/browser/gpu/gl_string_manager.h"
56#include "chrome/browser/gpu/three_d_api_observer.h"
57#include "chrome/browser/media/media_capture_devices_dispatcher.h"
58#include "chrome/browser/metrics/field_trial_synchronizer.h"
59#include "chrome/browser/metrics/thread_watcher.h"
60#include "chrome/browser/metrics/variations/variations_service.h"
61#include "chrome/browser/nacl_host/nacl_browser_delegate_impl.h"
62#include "chrome/browser/net/chrome_net_log.h"
63#include "chrome/browser/net/crl_set_fetcher.h"
64#include "chrome/browser/notifications/desktop_notification_service.h"
65#include "chrome/browser/notifications/desktop_notification_service_factory.h"
66#include "chrome/browser/performance_monitor/performance_monitor.h"
67#include "chrome/browser/plugins/plugin_prefs.h"
68#include "chrome/browser/power/process_power_collector.h"
69#include "chrome/browser/pref_service_flags_storage.h"
70#include "chrome/browser/prefs/chrome_pref_service_factory.h"
71#include "chrome/browser/prefs/command_line_pref_store.h"
72#include "chrome/browser/prefs/pref_metrics_service.h"
73#include "chrome/browser/printing/cloud_print/cloud_print_proxy_service.h"
74#include "chrome/browser/printing/cloud_print/cloud_print_proxy_service_factory.h"
75#include "chrome/browser/process_singleton.h"
76#include "chrome/browser/profiles/profile.h"
77#include "chrome/browser/profiles/profile_manager.h"
78#include "chrome/browser/profiles/profiles_state.h"
79#include "chrome/browser/shell_integration.h"
80#include "chrome/browser/translate/translate_service.h"
81#include "chrome/browser/ui/app_list/app_list_service.h"
82#include "chrome/browser/ui/browser.h"
83#include "chrome/browser/ui/browser_finder.h"
84#include "chrome/browser/ui/host_desktop.h"
85#include "chrome/browser/ui/startup/bad_flags_prompt.h"
86#include "chrome/browser/ui/startup/default_browser_prompt.h"
87#include "chrome/browser/ui/startup/startup_browser_creator.h"
88#include "chrome/browser/ui/uma_browsing_activity_observer.h"
89#include "chrome/browser/ui/webui/chrome_web_ui_controller_factory.h"
90#include "chrome/common/chrome_constants.h"
91#include "chrome/common/chrome_paths.h"
92#include "chrome/common/chrome_result_codes.h"
93#include "chrome/common/chrome_switches.h"
94#include "chrome/common/crash_keys.h"
95#include "chrome/common/env_vars.h"
96#include "chrome/common/logging_chrome.h"
97#include "chrome/common/net/net_resource_provider.h"
98#include "chrome/common/pref_names.h"
99#include "chrome/common/profiling.h"
100#include "chrome/grit/generated_resources.h"
101#include "chrome/installer/util/google_update_settings.h"
102#include "components/component_updater/component_updater_service.h"
103#include "components/google/core/browser/google_util.h"
104#include "components/language_usage_metrics/language_usage_metrics.h"
105#include "components/metrics/metrics_service.h"
106#include "components/metrics/profiler/tracking_synchronizer.h"
107#include "components/nacl/browser/nacl_browser.h"
108#include "components/rappor/rappor_service.h"
109#include "components/signin/core/common/profile_management_switches.h"
110#include "components/startup_metric_utils/startup_metric_utils.h"
111#include "components/translate/content/common/cld_data_source.h"
112#include "components/translate/core/browser/translate_download_manager.h"
113#include "components/variations/variations_http_header_provider.h"
114#include "content/public/browser/browser_thread.h"
115#include "content/public/browser/notification_observer.h"
116#include "content/public/browser/notification_registrar.h"
117#include "content/public/browser/notification_service.h"
118#include "content/public/browser/notification_types.h"
119#include "content/public/browser/site_instance.h"
120#include "content/public/common/content_client.h"
121#include "content/public/common/content_switches.h"
122#include "content/public/common/main_function_params.h"
123#include "grit/platform_locale_settings.h"
124#include "net/base/net_module.h"
125#include "net/base/sdch_manager.h"
126#include "net/cookies/cookie_monster.h"
127#include "net/http/http_network_layer.h"
128#include "net/http/http_stream_factory.h"
129#include "net/url_request/url_request.h"
130#include "ui/base/l10n/l10n_util.h"
131#include "ui/base/layout.h"
132#include "ui/base/resource/resource_bundle.h"
133#include "ui/strings/grit/app_locale_settings.h"
134
135#if defined(OS_ANDROID)
136#include "chrome/browser/metrics/thread_watcher_android.h"
137#else
138#include "chrome/browser/feedback/feedback_profile_observer.h"
139#endif
140
141#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
142#include "chrome/browser/first_run/upgrade_util_linux.h"
143#include "chrome/browser/sxs_linux.h"
144#endif
145
146#if defined(OS_CHROMEOS)
147#include "chrome/browser/chromeos/settings/cros_settings.h"
148#include "chromeos/chromeos_switches.h"
149#include "chromeos/settings/cros_settings_names.h"
150#endif
151
152// TODO(port): several win-only methods have been pulled out of this, but
153// BrowserMain() as a whole needs to be broken apart so that it's usable by
154// other platforms. For now, it's just a stub. This is a serious work in
155// progress and should not be taken as an indication of a real refactoring.
156
157#if defined(OS_WIN)
158#include "base/environment.h"  // For PreRead experiment.
159#include "base/win/windows_version.h"
160#include "chrome/browser/browser_util_win.h"
161#include "chrome/browser/chrome_browser_main_win.h"
162#include "chrome/browser/chrome_select_file_dialog_factory_win.h"
163#include "chrome/browser/component_updater/sw_reporter_installer_win.h"
164#include "chrome/browser/first_run/try_chrome_dialog_view.h"
165#include "chrome/browser/first_run/upgrade_util_win.h"
166#include "chrome/browser/ui/network_profile_bubble.h"
167#include "chrome/installer/util/helper.h"
168#include "chrome/installer/util/install_util.h"
169#include "chrome/installer/util/shell_util.h"
170#include "net/base/net_util.h"
171#include "ui/base/l10n/l10n_util_win.h"
172#include "ui/gfx/win/dpi.h"
173#include "ui/shell_dialogs/select_file_dialog.h"
174#endif  // defined(OS_WIN)
175
176#if defined(OS_MACOSX)
177#include <Security/Security.h>
178
179#include "base/mac/scoped_nsautorelease_pool.h"
180#include "chrome/browser/mac/keystone_glue.h"
181#endif
182
183#if !defined(DISABLE_NACL)
184#include "chrome/browser/component_updater/pnacl/pnacl_component_installer.h"
185#include "components/nacl/browser/nacl_process_host.h"
186#endif
187
188#if defined(ENABLE_EXTENSIONS)
189#include "chrome/browser/extensions/startup_helper.h"
190#include "extensions/browser/extension_protocols.h"
191#endif
192
193#if defined(ENABLE_FULL_PRINTING) && !defined(OFFICIAL_BUILD)
194#include "printing/printed_document.h"
195#endif
196
197#if defined(ENABLE_RLZ)
198#include "chrome/browser/rlz/rlz.h"
199#endif
200
201#if defined(ENABLE_WEBRTC)
202#include "chrome/browser/media/webrtc_log_util.h"
203#endif
204
205#if defined(USE_AURA)
206#include "ui/aura/env.h"
207#endif
208
209using content::BrowserThread;
210
211namespace {
212
213// This function provides some ways to test crash and assertion handling
214// behavior of the program.
215void HandleTestParameters(const CommandLine& command_line) {
216  // This parameter causes an assertion.
217  if (command_line.HasSwitch(switches::kBrowserAssertTest)) {
218    DCHECK(false);
219  }
220
221  // This parameter causes a null pointer crash (crash reporter trigger).
222  if (command_line.HasSwitch(switches::kBrowserCrashTest)) {
223    int* bad_pointer = NULL;
224    *bad_pointer = 0;
225  }
226}
227
228#if !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
229void AddFirstRunNewTabs(StartupBrowserCreator* browser_creator,
230                        const std::vector<GURL>& new_tabs) {
231  for (std::vector<GURL>::const_iterator it = new_tabs.begin();
232       it != new_tabs.end(); ++it) {
233    if (it->is_valid())
234      browser_creator->AddFirstRunTab(*it);
235  }
236}
237#endif  // !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
238
239// Returns the new local state object, guaranteed non-NULL.
240// |local_state_task_runner| must be a shutdown-blocking task runner.
241PrefService* InitializeLocalState(
242    base::SequencedTaskRunner* local_state_task_runner,
243    const CommandLine& parsed_command_line) {
244  TRACE_EVENT0("startup", "ChromeBrowserMainParts::InitializeLocalState")
245  base::FilePath local_state_path;
246  PathService::Get(chrome::FILE_LOCAL_STATE, &local_state_path);
247  bool local_state_file_exists = base::PathExists(local_state_path);
248
249  // Load local state.  This includes the application locale so we know which
250  // locale dll to load.  This also causes local state prefs to be registered.
251  PrefService* local_state = g_browser_process->local_state();
252  DCHECK(local_state);
253
254#if defined(OS_WIN)
255  if (first_run::IsChromeFirstRun()) {
256    // During first run we read the google_update registry key to find what
257    // language the user selected when downloading the installer. This
258    // becomes our default language in the prefs.
259    // Other platforms obey the system locale.
260    base::string16 install_lang;
261    if (GoogleUpdateSettings::GetLanguage(&install_lang)) {
262      local_state->SetString(prefs::kApplicationLocale,
263                             base::UTF16ToASCII(install_lang));
264    }
265  }
266#endif  // defined(OS_WIN)
267
268  // If the local state file for the current profile doesn't exist and the
269  // parent profile command line flag is present, then we should inherit some
270  // local state from the parent profile.
271  // Checking that the local state file for the current profile doesn't exist
272  // is the most robust way to determine whether we need to inherit or not
273  // since the parent profile command line flag can be present even when the
274  // current profile is not a new one, and in that case we do not want to
275  // inherit and reset the user's setting.
276  //
277  // TODO(mnissler): We should probably just instantiate a
278  // JSONPrefStore here instead of an entire PrefService. Once this is
279  // addressed, the call to browser_prefs::RegisterLocalState can move
280  // to chrome_prefs::CreateLocalState.
281  if (!local_state_file_exists &&
282      parsed_command_line.HasSwitch(switches::kParentProfile)) {
283    base::FilePath parent_profile =
284        parsed_command_line.GetSwitchValuePath(switches::kParentProfile);
285    scoped_refptr<PrefRegistrySimple> registry = new PrefRegistrySimple();
286    scoped_ptr<PrefService> parent_local_state(
287        chrome_prefs::CreateLocalState(
288            parent_profile,
289            local_state_task_runner,
290            g_browser_process->policy_service(),
291            registry,
292            false));
293    registry->RegisterStringPref(prefs::kApplicationLocale, std::string());
294    // Right now, we only inherit the locale setting from the parent profile.
295    local_state->SetString(
296        prefs::kApplicationLocale,
297        parent_local_state->GetString(prefs::kApplicationLocale));
298  }
299
300#if defined(OS_CHROMEOS)
301  if (parsed_command_line.HasSwitch(chromeos::switches::kLoginManager)) {
302    std::string owner_locale = local_state->GetString(prefs::kOwnerLocale);
303    // Ensure that we start with owner's locale.
304    if (!owner_locale.empty() &&
305        local_state->GetString(prefs::kApplicationLocale) != owner_locale &&
306        !local_state->IsManagedPreference(prefs::kApplicationLocale)) {
307      local_state->SetString(prefs::kApplicationLocale, owner_locale);
308    }
309  }
310#endif
311
312  return local_state;
313}
314
315// Initializes the primary profile, possibly doing some user prompting to pick
316// a fallback profile. Returns the newly created profile, or NULL if startup
317// should not continue.
318Profile* CreatePrimaryProfile(const content::MainFunctionParams& parameters,
319                              const base::FilePath& user_data_dir,
320                              const CommandLine& parsed_command_line) {
321  TRACE_EVENT0("startup", "ChromeBrowserMainParts::CreateProfile")
322  base::Time start = base::Time::Now();
323  if (profiles::IsMultipleProfilesEnabled() &&
324      parsed_command_line.HasSwitch(switches::kProfileDirectory)) {
325    g_browser_process->local_state()->SetString(prefs::kProfileLastUsed,
326        parsed_command_line.GetSwitchValueASCII(switches::kProfileDirectory));
327    // Clear kProfilesLastActive since the user only wants to launch a specific
328    // profile.
329    ListPrefUpdate update(g_browser_process->local_state(),
330                          prefs::kProfilesLastActive);
331    base::ListValue* profile_list = update.Get();
332    profile_list->Clear();
333  }
334
335  Profile* profile = NULL;
336#if defined(OS_CHROMEOS) || defined(OS_ANDROID)
337  // On ChromeOS and Android the ProfileManager will use the same path as the
338  // one we got passed. GetActiveUserProfile will therefore use the correct path
339  // automatically.
340  DCHECK_EQ(user_data_dir.value(),
341            g_browser_process->profile_manager()->user_data_dir().value());
342  profile = ProfileManager::GetActiveUserProfile();
343#else
344  base::FilePath profile_path =
345      GetStartupProfilePath(user_data_dir, parsed_command_line);
346
347  // Without NewAvatarMenu, replace guest with any existing profile.
348  if (!switches::IsNewAvatarMenu() &&
349      profile_path == ProfileManager::GetGuestProfilePath()) {
350    profile_path = g_browser_process->profile_manager()->GetProfileInfoCache().
351        GetPathOfProfileAtIndex(0);
352  }
353  profile = g_browser_process->profile_manager()->GetProfile(
354      profile_path);
355
356  // If we're using the --new-profile-management flag and this profile is
357  // signed out, then we should show the user manager instead. By switching
358  // the active profile to the guest profile we ensure that no
359  // browser windows will be opened for the guest profile.
360  if (switches::IsNewProfileManagement() && !profile->IsGuestSession()) {
361    ProfileInfoCache& cache =
362        g_browser_process->profile_manager()->GetProfileInfoCache();
363    size_t profile_index = cache.GetIndexOfProfileWithPath(profile_path);
364
365    if (cache.ProfileIsSigninRequiredAtIndex(profile_index))
366      profile = g_browser_process->profile_manager()->GetProfile(
367          ProfileManager::GetGuestProfilePath());
368  }
369#endif
370  if (profile) {
371    UMA_HISTOGRAM_LONG_TIMES(
372        "Startup.CreateFirstProfile", base::Time::Now() - start);
373    return profile;
374  }
375
376#if !defined(OS_WIN)
377  // TODO(port): fix this.  See comments near the definition of
378  // user_data_dir.  It is better to CHECK-fail here than it is to
379  // silently exit because of missing code in the above test.
380  CHECK(profile) << "Cannot get default profile.";
381#endif
382
383  return NULL;
384}
385
386#if defined(OS_MACOSX)
387OSStatus KeychainCallback(SecKeychainEvent keychain_event,
388                          SecKeychainCallbackInfo* info, void* context) {
389  return noErr;
390}
391#endif
392
393void RegisterComponentsForUpdate() {
394  component_updater::ComponentUpdateService* cus =
395      g_browser_process->component_updater();
396
397  // Registration can be before or after cus->Start() so it is ok to post
398  // a task to the UI thread to do registration once you done the necessary
399  // file IO to know you existing component version.
400#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
401  RegisterRecoveryComponent(cus, g_browser_process->local_state());
402  RegisterPepperFlashComponent(cus);
403  RegisterSwiftShaderComponent(cus);
404  RegisterWidevineCdmComponent(cus);
405#if !defined(DISABLE_NACL)
406  g_browser_process->pnacl_component_installer()->RegisterPnaclComponent(cus);
407#endif
408#endif
409
410  if (translate::CldDataSource::ShouldRegisterForComponentUpdates()) {
411    RegisterCldComponent(cus);
412  }
413
414  base::FilePath path;
415  if (PathService::Get(chrome::DIR_USER_DATA, &path)) {
416#if defined(OS_ANDROID)
417    // The CRLSet component was enabled for some releases. This code attempts to
418    // delete it from the local disk of those how may have downloaded it.
419    g_browser_process->crl_set_fetcher()->DeleteFromDisk(path);
420#elif !defined(OS_CHROMEOS)
421    // CRLSetFetcher attempts to load a CRL set from either the local disk or
422    // network.
423    // For Chrome OS this registration is delayed until user login.
424    g_browser_process->crl_set_fetcher()->StartInitialLoad(cus, path);
425#endif
426  }
427
428#if !defined(OS_ANDROID)
429  // Android does not currently have the EV indicator. No need to get the
430  // EV certs whitelist on Android, then.
431  RegisterEVWhitelistComponent(cus);
432#endif
433
434#if defined(OS_WIN)
435  RegisterSwReporterComponent(cus, g_browser_process->local_state());
436#endif
437
438  cus->Start();
439}
440
441#if !defined(OS_ANDROID)
442bool ProcessSingletonNotificationCallback(
443    const CommandLine& command_line,
444    const base::FilePath& current_directory) {
445  // Drop the request if the browser process is already in shutdown path.
446  if (!g_browser_process || g_browser_process->IsShuttingDown())
447    return false;
448
449  if (command_line.HasSwitch(switches::kOriginalProcessStartTime)) {
450    std::string start_time_string =
451        command_line.GetSwitchValueASCII(switches::kOriginalProcessStartTime);
452    int64 remote_start_time;
453    if (base::StringToInt64(start_time_string, &remote_start_time)) {
454      base::TimeDelta elapsed =
455          base::Time::Now() - base::Time::FromInternalValue(remote_start_time);
456      if (command_line.HasSwitch(switches::kFastStart)) {
457        UMA_HISTOGRAM_LONG_TIMES(
458            "Startup.WarmStartTimeFromRemoteProcessStartFast", elapsed);
459      } else {
460        UMA_HISTOGRAM_LONG_TIMES(
461            "Startup.WarmStartTimeFromRemoteProcessStart", elapsed);
462      }
463    }
464  }
465
466  g_browser_process->platform_part()->PlatformSpecificCommandLineProcessing(
467      command_line);
468
469  base::FilePath user_data_dir =
470      g_browser_process->profile_manager()->user_data_dir();
471  base::FilePath startup_profile_dir =
472      GetStartupProfilePath(user_data_dir, command_line);
473
474  StartupBrowserCreator::ProcessCommandLineAlreadyRunning(
475      command_line, current_directory, startup_profile_dir);
476  return true;
477}
478#endif  // !defined(OS_ANDROID)
479
480void LaunchDevToolsHandlerIfNeeded(const CommandLine& command_line) {
481  if (command_line.HasSwitch(::switches::kRemoteDebuggingPort)) {
482    std::string port_str =
483        command_line.GetSwitchValueASCII(::switches::kRemoteDebuggingPort);
484    int port;
485    if (base::StringToInt(port_str, &port) && port >= 0 && port < 65535) {
486      g_browser_process->CreateDevToolsHttpProtocolHandler(
487          chrome::HOST_DESKTOP_TYPE_NATIVE,
488          "127.0.0.1",
489          port);
490    } else {
491      DLOG(WARNING) << "Invalid http debugger port number " << port;
492    }
493  }
494}
495
496// Heap allocated class that listens for first page load, kicks off stat
497// recording and then deletes itself.
498class LoadCompleteListener : public content::NotificationObserver {
499 public:
500  LoadCompleteListener() {
501    registrar_.Add(this,
502                   content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
503                   content::NotificationService::AllSources());
504  }
505  virtual ~LoadCompleteListener() {}
506
507  // content::NotificationObserver implementation.
508  virtual void Observe(int type,
509                       const content::NotificationSource& source,
510                       const content::NotificationDetails& details) OVERRIDE {
511    DCHECK_EQ(content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME, type);
512    startup_metric_utils::OnInitialPageLoadComplete();
513    delete this;
514  }
515
516 private:
517  content::NotificationRegistrar registrar_;
518  DISALLOW_COPY_AND_ASSIGN(LoadCompleteListener);
519};
520
521}  // namespace
522
523namespace chrome_browser {
524
525// This error message is not localized because we failed to load the
526// localization data files.
527#if defined(OS_WIN)
528const char kMissingLocaleDataTitle[] = "Missing File Error";
529#endif
530
531#if defined(OS_WIN)
532// TODO(port) This should be used on Linux Aura as well. http://crbug.com/338969
533const char kMissingLocaleDataMessage[] =
534    "Unable to find locale data files. Please reinstall.";
535#endif
536
537}  // namespace chrome_browser
538
539// BrowserMainParts ------------------------------------------------------------
540
541// static
542bool ChromeBrowserMainParts::disable_enforcing_cookie_policies_for_tests_ =
543    false;
544
545ChromeBrowserMainParts::ChromeBrowserMainParts(
546    const content::MainFunctionParams& parameters)
547    : parameters_(parameters),
548      parsed_command_line_(parameters.command_line),
549      result_code_(content::RESULT_CODE_NORMAL_EXIT),
550      startup_watcher_(new StartupTimeBomb()),
551      shutdown_watcher_(new ShutdownWatcherHelper()),
552      browser_field_trials_(parameters.command_line),
553      profile_(NULL),
554      run_message_loop_(true),
555      notify_result_(ProcessSingleton::PROCESS_NONE),
556      local_state_(NULL),
557      restart_last_session_(false) {
558  // If we're running tests (ui_task is non-null).
559  if (parameters.ui_task)
560    browser_defaults::enable_help_app = false;
561
562  // Chrome disallows cookies by default. All code paths that want to use
563  // cookies need to go through one of Chrome's URLRequestContexts which have
564  // a ChromeNetworkDelegate attached that selectively allows cookies again.
565  if (!disable_enforcing_cookie_policies_for_tests_)
566    net::URLRequest::SetDefaultCookiePolicyToBlock();
567}
568
569ChromeBrowserMainParts::~ChromeBrowserMainParts() {
570  for (int i = static_cast<int>(chrome_extra_parts_.size())-1; i >= 0; --i)
571    delete chrome_extra_parts_[i];
572  chrome_extra_parts_.clear();
573}
574
575// This will be called after the command-line has been mutated by about:flags
576void ChromeBrowserMainParts::SetupMetricsAndFieldTrials() {
577  TRACE_EVENT0("startup", "ChromeBrowserMainParts::SetupMetricsAndFieldTrials");
578  // Must initialize metrics after labs have been converted into switches,
579  // but before field trials are set up (so that client ID is available for
580  // one-time randomized field trials).
581
582  // Initialize FieldTrialList to support FieldTrials that use one-time
583  // randomization.
584  metrics::MetricsService* metrics = browser_process_->metrics_service();
585  field_trial_list_.reset(
586      new base::FieldTrialList(metrics->CreateEntropyProvider().release()));
587
588  const CommandLine* command_line = CommandLine::ForCurrentProcess();
589  if (command_line->HasSwitch(switches::kEnableBenchmarking))
590    base::FieldTrial::EnableBenchmarking();
591
592  // Ensure any field trials specified on the command line are initialized.
593  if (command_line->HasSwitch(switches::kForceFieldTrials)) {
594    std::set<std::string> unforceable_field_trials;
595#if defined(OFFICIAL_BUILD)
596    unforceable_field_trials.insert("SettingsEnforcement");
597#endif  // defined(OFFICIAL_BUILD)
598
599    // Create field trials without activating them, so that this behaves in a
600    // consistent manner with field trials created from the server.
601    bool result = base::FieldTrialList::CreateTrialsFromString(
602        command_line->GetSwitchValueASCII(switches::kForceFieldTrials),
603        base::FieldTrialList::DONT_ACTIVATE_TRIALS,
604        unforceable_field_trials);
605    CHECK(result) << "Invalid --" << switches::kForceFieldTrials
606                  << " list specified.";
607  }
608  if (command_line->HasSwitch(switches::kForceVariationIds)) {
609    // Create default variation ids which will always be included in the
610    // X-Client-Data request header.
611    variations::VariationsHttpHeaderProvider* provider =
612        variations::VariationsHttpHeaderProvider::GetInstance();
613    bool result = provider->SetDefaultVariationIds(
614        command_line->GetSwitchValueASCII(switches::kForceVariationIds));
615    CHECK(result) << "Invalid --" << switches::kForceVariationIds
616                  << " list specified.";
617  }
618  chrome_variations::VariationsService* variations_service =
619      browser_process_->variations_service();
620  if (variations_service)
621    variations_service->CreateTrialsFromSeed();
622
623  // This must be called after |local_state_| is initialized.
624  browser_field_trials_.SetupFieldTrials(
625      base::Time::FromTimeT(metrics->GetInstallDate()), local_state_);
626
627  // Initialize FieldTrialSynchronizer system. This is a singleton and is used
628  // for posting tasks via base::Bind. Its deleted when it goes out of scope.
629  // Even though base::Bind does AddRef and Release, the object will not be
630  // deleted after the Task is executed.
631  field_trial_synchronizer_ = new FieldTrialSynchronizer();
632
633  // Now that field trials have been created, initializes metrics recording.
634  metrics->InitializeMetricsRecordingState();
635}
636
637// ChromeBrowserMainParts: |SetupMetricsAndFieldTrials()| related --------------
638
639void ChromeBrowserMainParts::StartMetricsRecording() {
640  TRACE_EVENT0("startup", "ChromeBrowserMainParts::StartMetricsRecording");
641  metrics::MetricsService* metrics = g_browser_process->metrics_service();
642
643  const bool only_do_metrics_recording =
644      parsed_command_line_.HasSwitch(switches::kMetricsRecordingOnly) ||
645      parsed_command_line_.HasSwitch(switches::kEnableBenchmarking);
646  if (only_do_metrics_recording) {
647    // If we're testing then we don't care what the user preference is, we turn
648    // on recording, but not reporting, otherwise tests fail.
649    metrics->StartRecordingForTests();
650    return;
651  }
652
653  metrics->CheckForClonedInstall(
654      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE));
655  const bool metrics_enabled = metrics->StartIfMetricsReportingEnabled();
656  // TODO(asvitkine): Since this function is not run on Android, RAPPOR is
657  // currently disabled there. http://crbug.com/370041
658  browser_process_->rappor_service()->Start(
659      browser_process_->system_request_context(),
660      metrics_enabled);
661}
662
663void ChromeBrowserMainParts::RecordBrowserStartupTime() {
664  // Don't record any metrics if UI was displayed before this point e.g.
665  // warning dialogs.
666  if (startup_metric_utils::WasNonBrowserUIDisplayed())
667    return;
668
669#if defined(OS_ANDROID)
670  // On Android the first run is handled in Java code, and the C++ side of
671  // Chrome doesn't know if this is the first run. This will cause some
672  // inaccuracy in the UMA statistics, but this should be minor (first runs are
673  // rare).
674  bool is_first_run = false;
675#else
676  bool is_first_run = first_run::IsChromeFirstRun();
677#endif
678
679// CurrentProcessInfo::CreationTime() is currently only implemented on some
680// platforms.
681#if defined(OS_MACOSX) || defined(OS_WIN) || defined(OS_LINUX)
682  const base::Time process_creation_time =
683      base::CurrentProcessInfo::CreationTime();
684
685  if (!is_first_run && !process_creation_time.is_null()) {
686    base::TimeDelta delay = base::Time::Now() - process_creation_time;
687    UMA_HISTOGRAM_LONG_TIMES_100("Startup.BrowserMessageLoopStartTime", delay);
688  }
689#endif  // defined(OS_MACOSX) || defined(OS_WIN) || defined(OS_LINUX)
690
691  // Record collected startup metrics.
692  startup_metric_utils::OnBrowserStartupComplete(is_first_run);
693
694  // Deletes self.
695  new LoadCompleteListener();
696}
697
698// -----------------------------------------------------------------------------
699// TODO(viettrungluu): move more/rest of BrowserMain() into BrowserMainParts.
700
701#if defined(OS_WIN)
702#define DLLEXPORT __declspec(dllexport)
703
704// We use extern C for the prototype DLLEXPORT to avoid C++ name mangling.
705extern "C" {
706DLLEXPORT void __cdecl RelaunchChromeBrowserWithNewCommandLineIfNeeded();
707}
708
709DLLEXPORT void __cdecl RelaunchChromeBrowserWithNewCommandLineIfNeeded() {
710  // Need an instance of AtExitManager to handle singleton creations and
711  // deletions.  We need this new instance because, the old instance created
712  // in ChromeMain() got destructed when the function returned.
713  base::AtExitManager exit_manager;
714  upgrade_util::RelaunchChromeBrowserWithNewCommandLineIfNeeded();
715}
716#endif
717
718// content::BrowserMainParts implementation ------------------------------------
719
720void ChromeBrowserMainParts::PreEarlyInitialization() {
721  TRACE_EVENT0("startup", "ChromeBrowserMainParts::PreEarlyInitialization");
722  for (size_t i = 0; i < chrome_extra_parts_.size(); ++i)
723    chrome_extra_parts_[i]->PreEarlyInitialization();
724}
725
726void ChromeBrowserMainParts::PostEarlyInitialization() {
727  TRACE_EVENT0("startup", "ChromeBrowserMainParts::PostEarlyInitialization");
728  for (size_t i = 0; i < chrome_extra_parts_.size(); ++i)
729    chrome_extra_parts_[i]->PostEarlyInitialization();
730}
731
732void ChromeBrowserMainParts::ToolkitInitialized() {
733  TRACE_EVENT0("startup", "ChromeBrowserMainParts::ToolkitInitialized");
734  for (size_t i = 0; i < chrome_extra_parts_.size(); ++i)
735    chrome_extra_parts_[i]->ToolkitInitialized();
736}
737
738void ChromeBrowserMainParts::PreMainMessageLoopStart() {
739  TRACE_EVENT0("startup", "ChromeBrowserMainParts::PreMainMessageLoopStart");
740  for (size_t i = 0; i < chrome_extra_parts_.size(); ++i)
741    chrome_extra_parts_[i]->PreMainMessageLoopStart();
742}
743
744void ChromeBrowserMainParts::PostMainMessageLoopStart() {
745  TRACE_EVENT0("startup", "ChromeBrowserMainParts::PostMainMessageLoopStart");
746  for (size_t i = 0; i < chrome_extra_parts_.size(); ++i)
747    chrome_extra_parts_[i]->PostMainMessageLoopStart();
748}
749
750int ChromeBrowserMainParts::PreCreateThreads() {
751  TRACE_EVENT0("startup", "ChromeBrowserMainParts::PreCreateThreads");
752  result_code_ = PreCreateThreadsImpl();
753
754  if (result_code_ == content::RESULT_CODE_NORMAL_EXIT) {
755#if !defined(OS_ANDROID)
756    // These members must be initialized before exiting this function normally.
757    DCHECK(master_prefs_.get());
758    DCHECK(browser_creator_.get());
759#endif
760    for (size_t i = 0; i < chrome_extra_parts_.size(); ++i)
761      chrome_extra_parts_[i]->PreCreateThreads();
762  }
763
764  return result_code_;
765}
766
767int ChromeBrowserMainParts::PreCreateThreadsImpl() {
768  TRACE_EVENT0("startup", "ChromeBrowserMainParts::PreCreateThreadsImpl")
769  run_message_loop_ = false;
770#if !defined(OS_ANDROID)
771  chrome::MaybeShowInvalidUserDataDirWarningDialog();
772#endif
773  if (!PathService::Get(chrome::DIR_USER_DATA, &user_data_dir_))
774    return chrome::RESULT_CODE_MISSING_DATA;
775
776  // Force MediaCaptureDevicesDispatcher to be created on UI thread.
777  MediaCaptureDevicesDispatcher::GetInstance();
778
779  // Android's first run is done in Java instead of native.
780#if !defined(OS_ANDROID)
781  process_singleton_.reset(new ChromeProcessSingleton(
782      user_data_dir_, base::Bind(&ProcessSingletonNotificationCallback)));
783
784  // Cache first run state early.
785  first_run::IsChromeFirstRun();
786#endif
787
788  scoped_refptr<base::SequencedTaskRunner> local_state_task_runner =
789      JsonPrefStore::GetTaskRunnerForFile(
790          base::FilePath(chrome::kLocalStorePoolName),
791          BrowserThread::GetBlockingPool());
792
793  {
794    TRACE_EVENT0("startup",
795      "ChromeBrowserMainParts::PreCreateThreadsImpl:InitBrowswerProcessImpl");
796    browser_process_.reset(new BrowserProcessImpl(local_state_task_runner.get(),
797                                                  parsed_command_line()));
798  }
799
800  if (parsed_command_line().HasSwitch(switches::kEnableProfiling)) {
801    TRACE_EVENT0("startup",
802        "ChromeBrowserMainParts::PreCreateThreadsImpl:InitProfiling");
803    // User wants to override default tracking status.
804    std::string flag =
805      parsed_command_line().GetSwitchValueASCII(switches::kEnableProfiling);
806    // Default to basic profiling (no parent child support).
807    tracked_objects::ThreadData::Status status =
808          tracked_objects::ThreadData::PROFILING_ACTIVE;
809    if (flag.compare("0") != 0)
810      status = tracked_objects::ThreadData::DEACTIVATED;
811    else if (flag.compare("child") != 0)
812      status = tracked_objects::ThreadData::PROFILING_CHILDREN_ACTIVE;
813    tracked_objects::ThreadData::InitializeAndSetTrackingStatus(status);
814  }
815
816  if (parsed_command_line().HasSwitch(switches::kProfilingOutputFile)) {
817    tracking_objects_.set_output_file_path(
818        parsed_command_line().GetSwitchValuePath(
819            switches::kProfilingOutputFile));
820  }
821
822  local_state_ = InitializeLocalState(
823      local_state_task_runner.get(), parsed_command_line());
824
825#if !defined(OS_ANDROID)
826  // These members must be initialized before returning from this function.
827  master_prefs_.reset(new first_run::MasterPrefs);
828  // Android doesn't use StartupBrowserCreator.
829  browser_creator_.reset(new StartupBrowserCreator);
830  // TODO(yfriedman): Refactor Android to re-use UMABrowsingActivityObserver
831  chrome::UMABrowsingActivityObserver::Init();
832#endif
833
834#if !defined(OS_CHROMEOS)
835  // Convert active labs into switches. This needs to be done before
836  // ResourceBundle::InitSharedInstanceWithLocale as some loaded resources are
837  // affected by experiment flags (--touch-optimized-ui in particular).
838  // On ChromeOS system level flags are applied from the device settings from
839  // the session manager.
840  {
841    TRACE_EVENT0("startup",
842        "ChromeBrowserMainParts::PreCreateThreadsImpl:ConvertFlags");
843    about_flags::PrefServiceFlagsStorage flags_storage_(
844        g_browser_process->local_state());
845    about_flags::ConvertFlagsToSwitches(&flags_storage_,
846                                        CommandLine::ForCurrentProcess(),
847                                        about_flags::kAddSentinels);
848  }
849#endif
850
851  local_state_->UpdateCommandLinePrefStore(
852      new CommandLinePrefStore(CommandLine::ForCurrentProcess()));
853
854  // Reset the command line in the crash report details, since we may have
855  // just changed it to include experiments.
856  crash_keys::SetSwitchesFromCommandLine(CommandLine::ForCurrentProcess());
857
858  // Mac starts it earlier in |PreMainMessageLoopStart()| (because it is
859  // needed when loading the MainMenu.nib and the language doesn't depend on
860  // anything since it comes from Cocoa.
861#if defined(OS_MACOSX)
862  std::string locale =
863      parameters().ui_task ? "en-US" : l10n_util::GetLocaleOverride();
864  browser_process_->SetApplicationLocale(locale);
865#else
866  const std::string locale =
867      local_state_->GetString(prefs::kApplicationLocale);
868
869  // On a POSIX OS other than ChromeOS, the parameter that is passed to the
870  // method InitSharedInstance is ignored.
871
872  TRACE_EVENT_BEGIN0("startup",
873      "ChromeBrowserMainParts::PreCreateThreadsImpl:InitResourceBundle");
874  const std::string loaded_locale =
875      ui::ResourceBundle::InitSharedInstanceWithLocale(
876          locale, NULL, ui::ResourceBundle::LOAD_COMMON_RESOURCES);
877  TRACE_EVENT_END0("startup",
878      "ChromeBrowserMainParts::PreCreateThreadsImpl:InitResourceBundle");
879
880  if (loaded_locale.empty() &&
881      !parsed_command_line().HasSwitch(switches::kNoErrorDialogs)) {
882    ShowMissingLocaleMessageBox();
883    return chrome::RESULT_CODE_MISSING_DATA;
884  }
885  CHECK(!loaded_locale.empty()) << "Locale could not be found for " << locale;
886  browser_process_->SetApplicationLocale(loaded_locale);
887
888  base::FilePath resources_pack_path;
889  PathService::Get(chrome::FILE_RESOURCES_PACK, &resources_pack_path);
890  {
891    TRACE_EVENT0("startup",
892        "ChromeBrowserMainParts::PreCreateThreadsImpl:AddDataPack");
893    ResourceBundle::GetSharedInstance().AddDataPackFromPath(
894        resources_pack_path, ui::SCALE_FACTOR_NONE);
895  }
896#endif  // defined(OS_MACOSX)
897
898  // Android does first run in Java instead of native.
899  // Chrome OS has its own out-of-box-experience code.
900#if !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
901  // On first run, we need to process the predictor preferences before the
902  // browser's profile_manager object is created, but after ResourceBundle
903  // is initialized.
904  if (first_run::IsChromeFirstRun()) {
905    first_run::ProcessMasterPreferencesResult pmp_result =
906        first_run::ProcessMasterPreferences(user_data_dir_,
907                                            master_prefs_.get());
908    if (pmp_result == first_run::EULA_EXIT_NOW)
909      return chrome::RESULT_CODE_EULA_REFUSED;
910
911    if (!parsed_command_line().HasSwitch(switches::kApp) &&
912        !parsed_command_line().HasSwitch(switches::kAppId) &&
913        !parsed_command_line().HasSwitch(switches::kShowAppList)) {
914      AddFirstRunNewTabs(browser_creator_.get(), master_prefs_->new_tabs);
915    }
916
917    // TODO(macourteau): refactor preferences that are copied from
918    // master_preferences into local_state, as a "local_state" section in
919    // master preferences. If possible, a generic solution would be preferred
920    // over a copy one-by-one of specific preferences. Also see related TODO
921    // in first_run.h.
922
923    // Store the initial VariationsService seed in local state, if it exists
924    // in master prefs.
925    if (!master_prefs_->variations_seed.empty()) {
926      local_state_->SetString(prefs::kVariationsSeed,
927                              master_prefs_->variations_seed);
928      if (!master_prefs_->variations_seed_signature.empty()) {
929        local_state_->SetString(prefs::kVariationsSeedSignature,
930                                master_prefs_->variations_seed_signature);
931      }
932      // Set the variation seed date to the current system time. If the user's
933      // clock is incorrect, this may cause some field trial expiry checks to
934      // not do the right thing until the next seed update from the server,
935      // when this value will be updated.
936      local_state_->SetInt64(prefs::kVariationsSeedDate,
937                             base::Time::Now().ToInternalValue());
938    }
939
940    if (!master_prefs_->suppress_default_browser_prompt_for_version.empty()) {
941      local_state_->SetString(
942          prefs::kBrowserSuppressDefaultBrowserPrompt,
943          master_prefs_->suppress_default_browser_prompt_for_version);
944    }
945
946    AppListService::Get(chrome::HOST_DESKTOP_TYPE_NATIVE)->HandleFirstRun();
947  }
948#endif
949
950#if defined(OS_LINUX) || defined(OS_OPENBSD) || defined(OS_MACOSX)
951  // Set the product channel for crash reports.
952  base::debug::SetCrashKeyValue(crash_keys::kChannel,
953      chrome::VersionInfo::GetVersionStringModifier());
954#endif
955
956  // Initialize tracking synchronizer system.
957  tracking_synchronizer_ = new metrics::TrackingSynchronizer();
958
959#if defined(OS_MACOSX)
960  // Get the Keychain API to register for distributed notifications on the main
961  // thread, which has a proper CFRunloop, instead of later on the I/O thread,
962  // which doesn't. This ensures those notifications will get delivered
963  // properly. See issue 37766.
964  // (Note that the callback mask here is empty. I don't want to register for
965  // any callbacks, I just want to initialize the mechanism.)
966  SecKeychainAddCallback(&KeychainCallback, 0, NULL);
967#endif
968
969#if defined(OS_CHROMEOS)
970  // Must be done after g_browser_process is constructed, before
971  // SetupMetricsAndFieldTrials().
972  chromeos::CrosSettings::Initialize();
973#endif
974
975  // Now the command line has been mutated based on about:flags, we can setup
976  // metrics and initialize field trials. The field trials are needed by
977  // IOThread's initialization which happens in BrowserProcess:PreCreateThreads.
978  SetupMetricsAndFieldTrials();
979
980  // ChromeOS needs ResourceBundle::InitSharedInstance to be called before this.
981  browser_process_->PreCreateThreads();
982
983  return content::RESULT_CODE_NORMAL_EXIT;
984}
985
986void ChromeBrowserMainParts::PreMainMessageLoopRun() {
987  TRACE_EVENT0("startup", "ChromeBrowserMainParts::PreMainMessageLoopRun");
988  result_code_ = PreMainMessageLoopRunImpl();
989
990  for (size_t i = 0; i < chrome_extra_parts_.size(); ++i)
991    chrome_extra_parts_[i]->PreMainMessageLoopRun();
992}
993
994// PreMainMessageLoopRun calls these extra stages in the following order:
995//  PreMainMessageLoopRunImpl()
996//   ... initial setup, including browser_process_ setup.
997//   PreProfileInit()
998//   ... additional setup, including CreateProfile()
999//   PostProfileInit()
1000//   ... additional setup
1001//   PreBrowserStart()
1002//   ... browser_creator_->Start (OR parameters().ui_task->Run())
1003//   PostBrowserStart()
1004
1005void ChromeBrowserMainParts::PreProfileInit() {
1006  TRACE_EVENT0("startup", "ChromeBrowserMainParts::PreProfileInit");
1007
1008  for (size_t i = 0; i < chrome_extra_parts_.size(); ++i)
1009    chrome_extra_parts_[i]->PreProfileInit();
1010
1011#if !defined(OS_ANDROID)
1012  // Initialize the feedback uploader so it can setup notifications for profile
1013  // creation.
1014  feedback::FeedbackProfileObserver::Initialize();
1015
1016  ProfileManager* profile_manager = g_browser_process->profile_manager();
1017
1018  // First check if any ephemeral profiles are left behind because of browser
1019  // crash and schedule them for deletion and then proceed with getting the set
1020  // of profiles to open.
1021  ProfileInfoCache& profile_cache = profile_manager->GetProfileInfoCache();
1022  size_t profiles_count = profile_cache.GetNumberOfProfiles();
1023  std::vector<base::FilePath> profiles_to_delete;
1024  for (size_t i = 0; i < profiles_count; ++i) {
1025    if (profile_cache.ProfileIsEphemeralAtIndex(i))
1026      profiles_to_delete.push_back(profile_cache.GetPathOfProfileAtIndex(i));
1027  }
1028
1029  if (profiles_to_delete.size()) {
1030    for (size_t i = 0; i < profiles_to_delete.size(); ++i) {
1031      profile_manager->ScheduleProfileForDeletion(
1032          profiles_to_delete[i], ProfileManager::CreateCallback());
1033    }
1034    // Clean up stale profiles immediately after browser start.
1035    BrowserThread::PostTask(
1036        BrowserThread::FILE, FROM_HERE,
1037        base::Bind(&ProfileManager::CleanUpStaleProfiles, profiles_to_delete));
1038  }
1039#endif  // OS_ANDROID
1040}
1041
1042void ChromeBrowserMainParts::PostProfileInit() {
1043  TRACE_EVENT0("startup", "ChromeBrowserMainParts::PostProfileInit");
1044  LaunchDevToolsHandlerIfNeeded(parsed_command_line());
1045  for (size_t i = 0; i < chrome_extra_parts_.size(); ++i)
1046    chrome_extra_parts_[i]->PostProfileInit();
1047}
1048
1049void ChromeBrowserMainParts::PreBrowserStart() {
1050  TRACE_EVENT0("startup", "ChromeBrowserMainParts::PreBrowserStart");
1051  for (size_t i = 0; i < chrome_extra_parts_.size(); ++i)
1052    chrome_extra_parts_[i]->PreBrowserStart();
1053
1054  three_d_observer_.reset(new ThreeDAPIObserver());
1055}
1056
1057void ChromeBrowserMainParts::PostBrowserStart() {
1058  TRACE_EVENT0("startup", "ChromeBrowserMainParts::PostBrowserStart");
1059  for (size_t i = 0; i < chrome_extra_parts_.size(); ++i)
1060    chrome_extra_parts_[i]->PostBrowserStart();
1061#if !defined(OS_ANDROID)
1062  // Allow ProcessSingleton to process messages.
1063  process_singleton_->Unlock();
1064#endif
1065#if defined(ENABLE_WEBRTC)
1066  // Set up a task to delete old WebRTC log files for all profiles. Use a delay
1067  // to reduce the impact on startup time.
1068  BrowserThread::PostDelayedTask(
1069      BrowserThread::UI,
1070      FROM_HERE,
1071      base::Bind(&WebRtcLogUtil::DeleteOldWebRtcLogFilesForAllProfiles),
1072      base::TimeDelta::FromMinutes(1));
1073#endif
1074}
1075
1076int ChromeBrowserMainParts::PreMainMessageLoopRunImpl() {
1077  TRACE_EVENT0("startup", "ChromeBrowserMainParts::PreMainMessageLoopRunImpl");
1078  // Android updates the metrics service dynamically depending on whether the
1079  // application is in the foreground or not. Do not start here.
1080#if !defined(OS_ANDROID)
1081  // Now that the file thread has been started, start recording.
1082  StartMetricsRecording();
1083#endif
1084
1085  // Create watchdog thread after creating all other threads because it will
1086  // watch the other threads and they must be running.
1087  browser_process_->watchdog_thread();
1088
1089  // Do any initializating in the browser process that requires all threads
1090  // running.
1091  browser_process_->PreMainMessageLoopRun();
1092
1093  // Record last shutdown time into a histogram.
1094  browser_shutdown::ReadLastShutdownInfo();
1095
1096#if defined(OS_WIN)
1097  // On Windows, we use our startup as an opportunity to do upgrade/uninstall
1098  // tasks.  Those care whether the browser is already running.  On Linux/Mac,
1099  // upgrade/uninstall happen separately.
1100  bool already_running = browser_util::IsBrowserAlreadyRunning();
1101
1102  // If the command line specifies 'uninstall' then we need to work here
1103  // unless we detect another chrome browser running.
1104  if (parsed_command_line().HasSwitch(switches::kUninstall)) {
1105    return DoUninstallTasks(already_running);
1106  }
1107
1108  if (parsed_command_line().HasSwitch(switches::kHideIcons) ||
1109      parsed_command_line().HasSwitch(switches::kShowIcons)) {
1110    return ChromeBrowserMainPartsWin::HandleIconsCommands(
1111        parsed_command_line_);
1112  }
1113
1114  ui::SelectFileDialog::SetFactory(new ChromeSelectFileDialogFactory(
1115      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO)));
1116#endif
1117
1118  if (parsed_command_line().HasSwitch(switches::kMakeDefaultBrowser)) {
1119    return ShellIntegration::SetAsDefaultBrowser() ?
1120        static_cast<int>(content::RESULT_CODE_NORMAL_EXIT) :
1121        static_cast<int>(chrome::RESULT_CODE_SHELL_INTEGRATION_FAILED);
1122  }
1123
1124#if defined(USE_AURA)
1125  // Make sure aura::Env has been initialized.
1126  CHECK(aura::Env::GetInstance());
1127#endif
1128
1129  // Android doesn't support extensions and doesn't implement ProcessSingleton.
1130#if !defined(OS_ANDROID)
1131  // If the command line specifies --pack-extension, attempt the pack extension
1132  // startup action and exit.
1133  if (parsed_command_line().HasSwitch(switches::kPackExtension)) {
1134    extensions::StartupHelper extension_startup_helper;
1135    if (extension_startup_helper.PackExtension(parsed_command_line()))
1136      return content::RESULT_CODE_NORMAL_EXIT;
1137    return chrome::RESULT_CODE_PACK_EXTENSION_ERROR;
1138  }
1139
1140  // If we're being launched just to check the connector policy, we are
1141  // short-lived and don't want to be passing that switch off.
1142  bool pass_command_line = !parsed_command_line().HasSwitch(
1143      switches::kCheckCloudPrintConnectorPolicy);
1144
1145  if (pass_command_line) {
1146    // When another process is running, use that process instead of starting a
1147    // new one. NotifyOtherProcess will currently give the other process up to
1148    // 20 seconds to respond. Note that this needs to be done before we attempt
1149    // to read the profile.
1150    notify_result_ = process_singleton_->NotifyOtherProcessOrCreate();
1151    switch (notify_result_) {
1152      case ProcessSingleton::PROCESS_NONE:
1153        // No process already running, fall through to starting a new one.
1154        break;
1155
1156      case ProcessSingleton::PROCESS_NOTIFIED:
1157#if defined(OS_POSIX) && !defined(OS_MACOSX)
1158        printf("%s\n", base::SysWideToNativeMB(base::UTF16ToWide(
1159            l10n_util::GetStringUTF16(IDS_USED_EXISTING_BROWSER))).c_str());
1160#endif
1161        // Having a differentiated return type for testing allows for tests to
1162        // verify proper handling of some switches. When not testing, stick to
1163        // the standard Unix convention of returning zero when things went as
1164        // expected.
1165        if (parsed_command_line().HasSwitch(switches::kTestType))
1166          return chrome::RESULT_CODE_NORMAL_EXIT_PROCESS_NOTIFIED;
1167        return content::RESULT_CODE_NORMAL_EXIT;
1168
1169      case ProcessSingleton::PROFILE_IN_USE:
1170        return chrome::RESULT_CODE_PROFILE_IN_USE;
1171
1172      case ProcessSingleton::LOCK_ERROR:
1173        LOG(ERROR) << "Failed to create a ProcessSingleton for your profile "
1174                      "directory. This means that running multiple instances "
1175                      "would start multiple browser processes rather than "
1176                      "opening a new window in the existing process. Aborting "
1177                      "now to avoid profile corruption.";
1178        return chrome::RESULT_CODE_PROFILE_IN_USE;
1179
1180      default:
1181        NOTREACHED();
1182    }
1183  }
1184#endif  // !defined(OS_ANDROID)
1185
1186  // Handle special early return paths (which couldn't be processed even earlier
1187  // as they require the process singleton to be held) first.
1188
1189  std::string try_chrome =
1190      parsed_command_line().GetSwitchValueASCII(switches::kTryChromeAgain);
1191  if (!try_chrome.empty()) {
1192#if defined(OS_WIN)
1193    // Setup.exe has determined that we need to run a retention experiment
1194    // and has lauched chrome to show the experiment UI. It is guaranteed that
1195    // no other Chrome is currently running as the process singleton was
1196    // sucessfully grabbed above.
1197    int try_chrome_int;
1198    base::StringToInt(try_chrome, &try_chrome_int);
1199    TryChromeDialogView::Result answer = TryChromeDialogView::Show(
1200        try_chrome_int,
1201        base::Bind(&ChromeProcessSingleton::SetActiveModalDialog,
1202                   base::Unretained(process_singleton_.get())));
1203    if (answer == TryChromeDialogView::NOT_NOW)
1204      return chrome::RESULT_CODE_NORMAL_EXIT_CANCEL;
1205    if (answer == TryChromeDialogView::UNINSTALL_CHROME)
1206      return chrome::RESULT_CODE_NORMAL_EXIT_EXP2;
1207    // At this point the user is willing to try chrome again.
1208    if (answer == TryChromeDialogView::TRY_CHROME_AS_DEFAULT) {
1209      // Only set in the unattended case, the interactive case is Windows 8.
1210      if (ShellIntegration::CanSetAsDefaultBrowser() ==
1211          ShellIntegration::SET_DEFAULT_UNATTENDED)
1212        ShellIntegration::SetAsDefaultBrowser();
1213    }
1214#else
1215    // We don't support retention experiments on Mac or Linux.
1216    return content::RESULT_CODE_NORMAL_EXIT;
1217#endif  // defined(OS_WIN)
1218  }
1219
1220#if defined(OS_WIN)
1221  // Do the tasks if chrome has been upgraded while it was last running.
1222  if (!already_running && upgrade_util::DoUpgradeTasks(parsed_command_line()))
1223    return content::RESULT_CODE_NORMAL_EXIT;
1224
1225  // Check if there is any machine level Chrome installed on the current
1226  // machine. If yes and the current Chrome process is user level, we do not
1227  // allow the user level Chrome to run. So we notify the user and uninstall
1228  // user level Chrome.
1229  // Note this check needs to happen here (after the process singleton was
1230  // obtained but before potentially creating the first run sentinel).
1231  if (ChromeBrowserMainPartsWin::CheckMachineLevelInstall())
1232    return chrome::RESULT_CODE_MACHINE_LEVEL_INSTALL_EXISTS;
1233#endif  // defined(OS_WIN)
1234
1235#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
1236  if (sxs_linux::ShouldMigrateUserDataDir())
1237    return sxs_linux::MigrateUserDataDir();
1238#endif  // defined(OS_LINUX) && !defined(OS_CHROMEOS)
1239
1240  // Desktop construction occurs here, (required before profile creation).
1241  PreProfileInit();
1242
1243  // Profile creation ----------------------------------------------------------
1244
1245  metrics::MetricsService::SetExecutionPhase(
1246      metrics::MetricsService::CREATE_PROFILE,
1247      g_browser_process->local_state());
1248  profile_ = CreatePrimaryProfile(parameters(),
1249                                  user_data_dir_,
1250                                  parsed_command_line());
1251  if (!profile_)
1252    return content::RESULT_CODE_NORMAL_EXIT;
1253
1254#if !defined(OS_ANDROID)
1255  // The first run sentinel must be created after the process singleton was
1256  // grabbed and no early return paths were otherwise hit above.
1257  first_run::CreateSentinelIfNeeded();
1258#endif  // !defined(OS_ANDROID)
1259
1260#if defined(ENABLE_BACKGROUND)
1261  // Autoload any profiles which are running background apps.
1262  // TODO(rlp): Do this on a separate thread. See http://crbug.com/99075.
1263  browser_process_->profile_manager()->AutoloadProfiles();
1264#endif
1265  // Post-profile init ---------------------------------------------------------
1266
1267  TranslateService::Initialize();
1268
1269  // Needs to be done before PostProfileInit, since login manager on CrOS is
1270  // called inside PostProfileInit.
1271  content::WebUIControllerFactory::RegisterFactory(
1272      ChromeWebUIControllerFactory::GetInstance());
1273
1274  // NaClBrowserDelegateImpl is accessed inside PostProfileInit().
1275  // So make sure to create it before that.
1276#if !defined(DISABLE_NACL)
1277  NaClBrowserDelegateImpl* delegate =
1278      new NaClBrowserDelegateImpl(browser_process_->profile_manager());
1279  nacl::NaClBrowser::SetDelegate(delegate);
1280#endif
1281
1282  // TODO(stevenjb): Move WIN and MACOSX specific code to appropriate Parts.
1283  // (requires supporting early exit).
1284  PostProfileInit();
1285
1286  // Retrieve cached GL strings from local state and use them for GPU
1287  // blacklist decisions.
1288  if (g_browser_process->gl_string_manager())
1289    g_browser_process->gl_string_manager()->Initialize();
1290
1291  // Create an instance of GpuModeManager to watch gpu mode pref change.
1292  g_browser_process->gpu_mode_manager();
1293
1294#if !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
1295  // Show the First Run UI if this is the first time Chrome has been run on
1296  // this computer, or we're being compelled to do so by a command line flag.
1297  // Note that this be done _after_ the PrefService is initialized and all
1298  // preferences are registered, since some of the code that the importer
1299  // touches reads preferences.
1300  if (first_run::IsChromeFirstRun()) {
1301    first_run::AutoImport(profile_,
1302                          master_prefs_->homepage_defined,
1303                          master_prefs_->do_import_items,
1304                          master_prefs_->dont_import_items,
1305                          master_prefs_->import_bookmarks_path);
1306
1307    // Note: this can pop the first run consent dialog on linux.
1308    first_run::DoPostImportTasks(profile_,
1309                                 master_prefs_->make_chrome_default_for_user);
1310
1311    if (!master_prefs_->suppress_first_run_default_browser_prompt) {
1312      browser_creator_->set_show_main_browser_window(
1313          !chrome::ShowFirstRunDefaultBrowserPrompt(profile_));
1314    } else {
1315      browser_creator_->set_is_default_browser_dialog_suppressed(true);
1316    }
1317  }
1318#endif  // !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
1319
1320#if defined(OS_WIN)
1321  // Sets things up so that if we crash from this point on, a dialog will
1322  // popup asking the user to restart chrome. It is done this late to avoid
1323  // testing against a bunch of special cases that are taken care early on.
1324  ChromeBrowserMainPartsWin::PrepareRestartOnCrashEnviroment(
1325      parsed_command_line());
1326
1327  // Registers Chrome with the Windows Restart Manager, which will restore the
1328  // Chrome session when the computer is restarted after a system update.
1329  // This could be run as late as WM_QUERYENDSESSION for system update reboots,
1330  // but should run on startup if extended to handle crashes/hangs/patches.
1331  // Also, better to run once here than once for each HWND's WM_QUERYENDSESSION.
1332  if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
1333    ChromeBrowserMainPartsWin::RegisterApplicationRestart(
1334        parsed_command_line());
1335  }
1336
1337  // Verify that the profile is not on a network share and if so prepare to show
1338  // notification to the user.
1339  if (NetworkProfileBubble::ShouldCheckNetworkProfile(profile_)) {
1340    BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
1341        base::Bind(&NetworkProfileBubble::CheckNetworkProfile,
1342                   profile_->GetPath()));
1343  }
1344#endif  // OS_WIN
1345
1346#if defined(ENABLE_RLZ) && !defined(OS_CHROMEOS)
1347  // Init the RLZ library. This just binds the dll and schedules a task on the
1348  // file thread to be run sometime later. If this is the first run we record
1349  // the installation event.
1350  PrefService* pref_service = profile_->GetPrefs();
1351  int ping_delay = first_run::IsChromeFirstRun() ? master_prefs_->ping_delay :
1352      pref_service->GetInteger(first_run::GetPingDelayPrefName().c_str());
1353  // Negative ping delay means to send ping immediately after a first search is
1354  // recorded.
1355  RLZTracker::InitRlzFromProfileDelayed(
1356      profile_, first_run::IsChromeFirstRun(), ping_delay < 0,
1357      base::TimeDelta::FromMilliseconds(abs(ping_delay)));
1358#endif  // defined(ENABLE_RLZ) && !defined(OS_CHROMEOS)
1359
1360  // Configure modules that need access to resources.
1361  net::NetModule::SetResourceProvider(chrome_common_net::NetResourceProvider);
1362
1363  // In unittest mode, this will do nothing.  In normal mode, this will create
1364  // the global IntranetRedirectDetector instance, which will promptly go to
1365  // sleep for seven seconds (to avoid slowing startup), and wake up afterwards
1366  // to see if it should do anything else.
1367  //
1368  // A simpler way of doing all this would be to have some function which could
1369  // give the time elapsed since startup, and simply have this object check that
1370  // when asked to initialize itself, but this doesn't seem to exist.
1371  //
1372  // This can't be created in the BrowserProcessImpl constructor because it
1373  // needs to read prefs that get set after that runs.
1374  browser_process_->intranet_redirect_detector();
1375  GoogleSearchCounter::RegisterForNotifications();
1376
1377  // Check SDCH field trial.  Default is now that everything is enabled,
1378  // so provide options for disabling HTTPS or all of SDCH.
1379  const char kSdchFieldTrialName[] = "SDCH";
1380  const char kEnabledHttpOnlyGroupName[] = "EnabledHttpOnly";
1381  const char kDisabledAllGroupName[] = "DisabledAll";
1382
1383  // Store in a string on return to keep underlying storage for
1384  // StringPiece stable.
1385  std::string sdch_trial_group_string =
1386      base::FieldTrialList::FindFullName(kSdchFieldTrialName);
1387  base::StringPiece sdch_trial_group(sdch_trial_group_string);
1388  if (sdch_trial_group.starts_with(kEnabledHttpOnlyGroupName)) {
1389    net::SdchManager::EnableSdchSupport(true);
1390    net::SdchManager::EnableSecureSchemeSupport(false);
1391  } else if (sdch_trial_group.starts_with(kDisabledAllGroupName)) {
1392    net::SdchManager::EnableSdchSupport(false);
1393  }
1394
1395#if defined(ENABLE_FULL_PRINTING) && !defined(OFFICIAL_BUILD)
1396  if (parsed_command_line().HasSwitch(switches::kDebugPrint)) {
1397    base::FilePath path =
1398        parsed_command_line().GetSwitchValuePath(switches::kDebugPrint);
1399    printing::PrintedDocument::set_debug_dump_path(path);
1400  }
1401#endif
1402
1403  HandleTestParameters(parsed_command_line());
1404  browser_process_->metrics_service()->RecordBreakpadHasDebugger(
1405      base::debug::BeingDebugged());
1406
1407  language_usage_metrics::LanguageUsageMetrics::RecordAcceptLanguages(
1408      profile_->GetPrefs()->GetString(prefs::kAcceptLanguages));
1409  language_usage_metrics::LanguageUsageMetrics::RecordApplicationLanguage(
1410      browser_process_->GetApplicationLocale());
1411
1412  // Start watching for hangs during startup. We disarm this hang detector when
1413  // ThreadWatcher takes over or when browser is shutdown or when
1414  // startup_watcher_ is deleted.
1415  metrics::MetricsService::SetExecutionPhase(
1416      metrics::MetricsService::STARTUP_TIMEBOMB_ARM,
1417      g_browser_process->local_state());
1418  startup_watcher_->Arm(base::TimeDelta::FromSeconds(600));
1419
1420  // On mobile, need for clean shutdown arises only when the application comes
1421  // to foreground (i.e. MetricsService::OnAppEnterForeground is called).
1422  // http://crbug.com/179143
1423#if !defined(OS_ANDROID)
1424  // Start watching for a hang.
1425  browser_process_->metrics_service()->LogNeedForCleanShutdown();
1426#endif
1427
1428#if defined(ENABLE_FULL_PRINTING)
1429  // Create the instance of the cloud print proxy service so that it can launch
1430  // the service process if needed. This is needed because the service process
1431  // might have shutdown because an update was available.
1432  // TODO(torne): this should maybe be done with
1433  // BrowserContextKeyedServiceFactory::ServiceIsCreatedWithBrowserContext()
1434  // instead?
1435  CloudPrintProxyServiceFactory::GetForProfile(profile_);
1436#endif
1437
1438  // Start watching all browser threads for responsiveness.
1439  metrics::MetricsService::SetExecutionPhase(
1440      metrics::MetricsService::THREAD_WATCHER_START,
1441      g_browser_process->local_state());
1442  ThreadWatcherList::StartWatchingAll(parsed_command_line());
1443
1444#if defined(OS_ANDROID)
1445  ThreadWatcherAndroid::RegisterApplicationStatusListener();
1446#endif
1447
1448#if !defined(DISABLE_NACL)
1449  BrowserThread::PostTask(
1450      BrowserThread::IO,
1451      FROM_HERE,
1452      base::Bind(nacl::NaClProcessHost::EarlyStartup));
1453#endif
1454
1455  // Make sure initial prefs are recorded
1456  PrefMetricsService::Factory::GetForProfile(profile_);
1457
1458  PreBrowserStart();
1459
1460  // Instantiate the notification UI manager, as this triggers a perf timer
1461  // used to measure startup time. TODO(stevenjb): Figure out what is actually
1462  // triggering the timer and call that explicitly in the approprate place.
1463  // http://crbug.com/105065.
1464  browser_process_->notification_ui_manager();
1465
1466  if (!parsed_command_line().HasSwitch(switches::kDisableComponentUpdate))
1467    RegisterComponentsForUpdate();
1468
1469#if defined(OS_ANDROID)
1470  chrome_variations::VariationsService* variations_service =
1471      browser_process_->variations_service();
1472  if (variations_service) {
1473    variations_service->set_policy_pref_service(profile_->GetPrefs());
1474    variations_service->StartRepeatedVariationsSeedFetch();
1475  }
1476  translate::TranslateDownloadManager::RequestLanguageList(
1477      profile_->GetPrefs());
1478
1479#else
1480  // Most general initialization is behind us, but opening a
1481  // tab and/or session restore and such is still to be done.
1482  base::TimeTicks browser_open_start = base::TimeTicks::Now();
1483
1484  // We are in regular browser boot sequence. Open initial tabs and enter the
1485  // main message loop.
1486  int result_code;
1487#if defined(OS_CHROMEOS)
1488  // On ChromeOS multiple profiles doesn't apply, and will break if we load
1489  // them this early as the cryptohome hasn't yet been mounted (which happens
1490  // only once we log in.
1491  std::vector<Profile*> last_opened_profiles;
1492#else
1493  std::vector<Profile*> last_opened_profiles =
1494      g_browser_process->profile_manager()->GetLastOpenedProfiles();
1495#endif
1496
1497  if (browser_creator_->Start(parsed_command_line(), base::FilePath(),
1498                              profile_, last_opened_profiles, &result_code)) {
1499#if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS))
1500    // Initialize autoupdate timer. Timer callback costs basically nothing
1501    // when browser is not in persistent mode, so it's OK to let it ride on
1502    // the main thread. This needs to be done here because we don't want
1503    // to start the timer when Chrome is run inside a test harness.
1504    browser_process_->StartAutoupdateTimer();
1505#endif
1506
1507#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
1508    // On Linux, the running exe will be updated if an upgrade becomes
1509    // available while the browser is running.  We need to save the last
1510    // modified time of the exe, so we can compare to determine if there is
1511    // an upgrade while the browser is kept alive by a persistent extension.
1512    upgrade_util::SaveLastModifiedTimeOfExe();
1513#endif
1514
1515    // Record now as the last successful chrome start.
1516    GoogleUpdateSettings::SetLastRunTime();
1517
1518#if defined(OS_MACOSX)
1519    // Call Recycle() here as late as possible, before going into the loop
1520    // because Start() will add things to it while creating the main window.
1521    if (parameters().autorelease_pool)
1522      parameters().autorelease_pool->Recycle();
1523#endif
1524
1525    base::TimeDelta delay = base::TimeTicks::Now() - browser_open_start;
1526    UMA_HISTOGRAM_LONG_TIMES_100("Startup.BrowserOpenTabs", delay);
1527
1528    // If we're running tests (ui_task is non-null), then we don't want to
1529    // call RequestLanguageList or StartRepeatedVariationsSeedFetch or
1530    // RequestLanguageList
1531    if (parameters().ui_task == NULL) {
1532      // Request new variations seed information from server.
1533      chrome_variations::VariationsService* variations_service =
1534          browser_process_->variations_service();
1535      if (variations_service) {
1536        variations_service->StartRepeatedVariationsSeedFetch();
1537
1538#if defined(OS_WIN)
1539        variations_service->StartGoogleUpdateRegistrySync();
1540#endif
1541      }
1542
1543      translate::TranslateDownloadManager::RequestLanguageList(
1544          profile_->GetPrefs());
1545    }
1546
1547    run_message_loop_ = true;
1548  } else {
1549    run_message_loop_ = false;
1550  }
1551  browser_creator_.reset();
1552#endif  // !defined(OS_ANDROID)
1553
1554#if !defined(OS_ANDROID)
1555  process_power_collector_.reset(new ProcessPowerCollector);
1556  process_power_collector_->Initialize();
1557#endif
1558
1559  PostBrowserStart();
1560
1561  if (parameters().ui_task) {
1562    parameters().ui_task->Run();
1563    delete parameters().ui_task;
1564    run_message_loop_ = false;
1565  }
1566#if defined(OS_ANDROID)
1567  // We never run the C++ main loop on Android, since the UI thread message
1568  // loop is controlled by the OS, so this is as close as we can get to
1569  // the start of the main loop
1570  if (result_code_ <= 0) {
1571    RecordBrowserStartupTime();
1572  }
1573#endif
1574  return result_code_;
1575}
1576
1577bool ChromeBrowserMainParts::MainMessageLoopRun(int* result_code) {
1578  TRACE_EVENT0("startup", "ChromeBrowserMainParts::MainMessageLoopRun");
1579#if defined(OS_ANDROID)
1580  // Chrome on Android does not use default MessageLoop. It has its own
1581  // Android specific MessageLoop
1582  NOTREACHED();
1583  return true;
1584#else
1585  // Set the result code set in PreMainMessageLoopRun or set above.
1586  *result_code = result_code_;
1587  if (!run_message_loop_)
1588    return true;  // Don't run the default message loop.
1589
1590  // These should be invoked as close to the start of the browser's
1591  // UI thread message loop as possible to get a stable measurement
1592  // across versions.
1593  RecordBrowserStartupTime();
1594
1595  DCHECK(base::MessageLoopForUI::IsCurrent());
1596  base::RunLoop run_loop;
1597
1598  performance_monitor::PerformanceMonitor::GetInstance()->StartGatherCycle();
1599
1600  metrics::MetricsService::SetExecutionPhase(
1601      metrics::MetricsService::MAIN_MESSAGE_LOOP_RUN,
1602      g_browser_process->local_state());
1603  run_loop.Run();
1604
1605  return true;
1606#endif
1607}
1608
1609void ChromeBrowserMainParts::PostMainMessageLoopRun() {
1610  TRACE_EVENT0("startup", "ChromeBrowserMainParts::PostMainMessageLoopRun");
1611#if defined(OS_ANDROID)
1612  // Chrome on Android does not use default MessageLoop. It has its own
1613  // Android specific MessageLoop
1614  NOTREACHED();
1615#else
1616
1617  // Start watching for jank during shutdown. It gets disarmed when
1618  // |shutdown_watcher_| object is destructed.
1619  metrics::MetricsService::SetExecutionPhase(
1620      metrics::MetricsService::SHUTDOWN_TIMEBOMB_ARM,
1621      g_browser_process->local_state());
1622  shutdown_watcher_->Arm(base::TimeDelta::FromSeconds(300));
1623
1624  // Disarm the startup hang detector time bomb if it is still Arm'ed.
1625  startup_watcher_->Disarm();
1626
1627  // Remove observers attached to D-Bus clients before DbusThreadManager is
1628  // shut down.
1629  process_power_collector_.reset();
1630
1631  for (size_t i = 0; i < chrome_extra_parts_.size(); ++i)
1632    chrome_extra_parts_[i]->PostMainMessageLoopRun();
1633
1634  // Some tests don't set parameters.ui_task, so they started translate
1635  // language fetch that was never completed so we need to cleanup here
1636  // otherwise it will be done by the destructor in a wrong thread.
1637  TranslateService::Shutdown(parameters().ui_task == NULL);
1638
1639  if (notify_result_ == ProcessSingleton::PROCESS_NONE)
1640    process_singleton_->Cleanup();
1641
1642  // Stop all tasks that might run on WatchDogThread.
1643  ThreadWatcherList::StopWatchingAll();
1644
1645  browser_process_->metrics_service()->Stop();
1646
1647  restart_last_session_ = browser_shutdown::ShutdownPreThreadsStop();
1648  browser_process_->StartTearDown();
1649#endif
1650}
1651
1652void ChromeBrowserMainParts::PostDestroyThreads() {
1653#if defined(OS_ANDROID)
1654  // On Android, there is no quit/exit. So the browser's main message loop will
1655  // not finish.
1656  NOTREACHED();
1657#else
1658  browser_process_->PostDestroyThreads();
1659  // browser_shutdown takes care of deleting browser_process, so we need to
1660  // release it.
1661  ignore_result(browser_process_.release());
1662  browser_shutdown::ShutdownPostThreadsStop(restart_last_session_);
1663  master_prefs_.reset();
1664  process_singleton_.reset();
1665
1666  // We need to do this check as late as possible, but due to modularity, this
1667  // may be the last point in Chrome.  This would be more effective if done at
1668  // a higher level on the stack, so that it is impossible for an early return
1669  // to bypass this code.  Perhaps we need a *final* hook that is called on all
1670  // paths from content/browser/browser_main.
1671  CHECK(metrics::MetricsService::UmaMetricsProperlyShutdown());
1672
1673#if defined(OS_CHROMEOS)
1674  chromeos::CrosSettings::Shutdown();
1675#endif
1676#endif
1677}
1678
1679// Public members:
1680
1681void ChromeBrowserMainParts::AddParts(ChromeBrowserMainExtraParts* parts) {
1682  chrome_extra_parts_.push_back(parts);
1683}
1684