text: // Copyright (c) 2012 The Chromium Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #include "chrome/browser/browser_process_impl.h"
  
  #include <algorithm>
  #include <map>
  #include <set>
  #include <vector>
  
  #include "base/bind.h"
  #include "base/bind_helpers.h"
  #include "base/command_line.h"
  #include "base/debug/alias.h"
  #include "base/file_util.h"
  #include "base/path_service.h"
  #include "base/prefs/json_pref_store.h"
  #include "base/synchronization/waitable_event.h"
  #include "base/threading/thread.h"
  #include "base/threading/thread_restrictions.h"
  #include "chrome/browser/automation/automation_provider_list.h"
  #include "chrome/browser/background/background_mode_manager.h"
  #include "chrome/browser/chrome_browser_main.h"
  #include "chrome/browser/chrome_content_browser_client.h"
  #include "chrome/browser/chrome_plugin_service_filter.h"
  #include "chrome/browser/component_updater/component_updater_configurator.h"
  #include "chrome/browser/component_updater/component_updater_service.h"
  #include "chrome/browser/debugger/remote_debugging_server.h"
  #include "chrome/browser/download/download_request_limiter.h"
  #include "chrome/browser/download/download_status_updater.h"
  #include "chrome/browser/extensions/event_router_forwarder.h"
  #include "chrome/browser/extensions/extension_tab_id_map.h"
  #include "chrome/browser/first_run/upgrade_util.h"
  #include "chrome/browser/icon_manager.h"
  #include "chrome/browser/intranet_redirect_detector.h"
  #include "chrome/browser/io_thread.h"
  #include "chrome/browser/lifetime/application_lifetime.h"
  #include "chrome/browser/metrics/metrics_service.h"
  #include "chrome/browser/metrics/thread_watcher.h"
  #include "chrome/browser/metrics/variations/variations_service.h"
  #include "chrome/browser/net/chrome_net_log.h"
  #include "chrome/browser/net/crl_set_fetcher.h"
  #include "chrome/browser/net/sdch_dictionary_fetcher.h"
  #include "chrome/browser/notifications/notification_ui_manager.h"
  #include "chrome/browser/plugins/plugin_finder.h"
  #include "chrome/browser/policy/policy_service.h"
  #include "chrome/browser/prefs/browser_prefs.h"
  #include "chrome/browser/prefs/pref_service.h"
  #include "chrome/browser/prerender/prerender_tracker.h"
  #include "chrome/browser/printing/background_printing_manager.h"
  #include "chrome/browser/printing/print_job_manager.h"
  #include "chrome/browser/printing/print_preview_tab_controller.h"
  #include "chrome/browser/profiles/profile_manager.h"
  #include "chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.h"
  #include "chrome/browser/safe_browsing/safe_browsing_service.h"
  #include "chrome/browser/shell_integration.h"
  #include "chrome/browser/status_icons/status_tray.h"
  #include "chrome/browser/thumbnails/render_widget_snapshot_taker.h"
  #include "chrome/browser/ui/browser_list.h"
  #include "chrome/common/chrome_constants.h"
  #include "chrome/common/chrome_content_client.h"
  #include "chrome/common/chrome_notification_types.h"
  #include "chrome/common/chrome_paths.h"
  #include "chrome/common/chrome_switches.h"
  #include "chrome/common/extensions/extension_l10n_util.h"
  #include "chrome/common/extensions/extension_resource.h"
  #include "chrome/common/pref_names.h"
  #include "chrome/common/switch_utils.h"
  #include "chrome/common/url_constants.h"
  #include "chrome/installer/util/google_update_constants.h"
  #include "content/public/browser/browser_thread.h"
  #include "content/public/browser/child_process_security_policy.h"
  #include "content/public/browser/notification_details.h"
  #include "content/public/browser/plugin_service.h"
  #include "content/public/browser/render_process_host.h"
  #include "content/public/browser/resource_dispatcher_host.h"
  #include "content/public/common/pepper_plugin_info.h"
  #include "net/socket/client_socket_pool_manager.h"
  #include "net/url_request/url_request_context_getter.h"
  #include "ui/base/l10n/l10n_util.h"
  
  #if defined(ENABLE_CONFIGURATION_POLICY)
  #include "chrome/browser/policy/browser_policy_connector.h"
  #else
  #include "chrome/browser/policy/policy_service_stub.h"
  #endif  // defined(ENABLE_CONFIGURATION_POLICY)
  
  #if defined(OS_WIN)
  #include "base/win/windows_version.h"
  #include "ui/views/focus/view_storage.h"
  #elif defined(OS_MACOSX)
  #include "chrome/browser/chrome_browser_main_mac.h"
  #endif
  
  #if defined(USE_AURA)
  #include "ui/aura/env.h"
  #endif
  
  #if defined(OS_CHROMEOS)
  #include "chrome/browser/chromeos/memory/oom_priority_manager.h"
  #endif  // defined(OS_CHROMEOS)
  
  #if defined(ENABLE_PLUGIN_INSTALLATION)
  #include "chrome/browser/web_resource/plugins_resource_service.h"
  #endif
  
  #if (defined(OS_WIN) || defined(OS_LINUX)) && !defined(OS_CHROMEOS)
  // How often to check if the persistent instance of Chrome needs to restart
  // to install an update.
  static const int kUpdateCheckIntervalHours = 6;
  #endif
  
  #if defined(OS_WIN)
  // Attest to the fact that the call to the file thread to save preferences has
  // run, and it is safe to terminate.  This avoids the potential of some other
  // task prematurely terminating our waiting message loop by posting a
  // QuitTask().
  static bool g_end_session_file_thread_has_completed = false;
  #endif
  
  #if defined(USE_X11)
  // How long to wait for the File thread to complete during EndSession, on
  // Linux. We have a timeout here because we're unable to run the UI messageloop
  // and there's some deadlock risk. Our only option is to exit anyway.
  static const int kEndSessionTimeoutSeconds = 10;
  #endif
  
  using content::BrowserThread;
  using content::ChildProcessSecurityPolicy;
  using content::PluginService;
  using content::ResourceDispatcherHost;
  
  BrowserProcessImpl::BrowserProcessImpl(const CommandLine& command_line)
      : created_metrics_service_(false),
        created_watchdog_thread_(false),
        created_browser_policy_connector_(false),
        created_profile_manager_(false),
        created_local_state_(false),
        created_icon_manager_(false),
        created_notification_ui_manager_(false),
        created_safe_browsing_service_(false),
        module_ref_count_(0),
        did_start_(false),
        checked_for_new_frames_(false),
        using_new_frames_(false),
        render_widget_snapshot_taker_(new RenderWidgetSnapshotTaker),
        download_status_updater_(new DownloadStatusUpdater) {
    g_browser_process = this;
  
  #if defined(ENABLE_PRINTING)
    // Must be created after the NotificationService.
    print_job_manager_.reset(new printing::PrintJobManager);
  #endif
  
    net_log_.reset(new ChromeNetLog);
  
    ChildProcessSecurityPolicy::GetInstance()->RegisterWebSafeScheme(
        chrome::kExtensionScheme);
    ChildProcessSecurityPolicy::GetInstance()->RegisterWebSafeScheme(
        chrome::kExtensionResourceScheme);
  
    extension_event_router_forwarder_ = new extensions::EventRouterForwarder;
  
    ExtensionTabIdMap::GetInstance()->Init();
  }
  
  BrowserProcessImpl::~BrowserProcessImpl() {
    tracked_objects::ThreadData::EnsureCleanupWasCalled(4);
  
    g_browser_process = NULL;
  }
  
  void BrowserProcessImpl::StartTearDown() {
  #if defined(ENABLE_AUTOMATION)
    // Delete the AutomationProviderList before NotificationService,
    // since it may try to unregister notifications
    // Both NotificationService and AutomationProvider are singleton instances in
    // the BrowserProcess. Since AutomationProvider may have some active
    // notification observers, it is essential that it gets destroyed before the
    // NotificationService. NotificationService won't be destroyed until after
    // this destructor is run.
    automation_provider_list_.reset();
  #endif
  
    // We need to shutdown the SdchDictionaryFetcher as it regularly holds
    // a pointer to a URLFetcher, and that URLFetcher (upon destruction) will do
    // a PostDelayedTask onto the IO thread.  This shutdown call will both discard
    // any pending URLFetchers, and avoid creating any more.
    BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
                            base::Bind(&SdchDictionaryFetcher::Shutdown));
  
    // We need to destroy the MetricsService, VariationsService,
    // IntranetRedirectDetector, and SafeBrowsing ClientSideDetectionService
    // (owned by the SafeBrowsingService) before the io_thread_ gets destroyed,
    // since their destructors can call the URLFetcher destructor, which does a
    // PostDelayedTask operation on the IO thread. (The IO thread will handle that
    // URLFetcher operation before going away.)
    metrics_service_.reset();
    variations_service_.reset();
    intranet_redirect_detector_.reset();
  #if defined(ENABLE_SAFE_BROWSING)
    if (safe_browsing_service_.get()) {
      safe_browsing_service()->ShutDown();
    }
  #endif
  
    // Need to clear the desktop notification balloons before the io_thread_ and
    // before the profiles, since if there are any still showing we will access
    // those things during teardown.
    notification_ui_manager_.reset();
  
    // Need to clear profiles (download managers) before the io_thread_.
    profile_manager_.reset();
  
  #if !defined(OS_ANDROID)
    // Debugger must be cleaned up before IO thread and NotificationService.
    remote_debugging_server_.reset();
  #endif
  
    ExtensionTabIdMap::GetInstance()->Shutdown();
  
  #if defined(ENABLE_CONFIGURATION_POLICY)
    // The policy providers managed by |browser_policy_connector_| need to shut
    // down while the IO and FILE threads are still alive.
    if (browser_policy_connector_)
      browser_policy_connector_->Shutdown();
  #endif
  
    // Stop the watchdog thread before stopping other threads.
    watchdog_thread_.reset();
  
  #if defined(USE_AURA)
    // Delete aura after the metrics service has been deleted as it accesses
    // monitor information.
    aura::Env::DeleteInstance();
  #endif
  }
  
  void BrowserProcessImpl::PostDestroyThreads() {
    // With the file_thread_ flushed, we can release any icon resources.
    icon_manager_.reset();
  
    // Reset associated state right after actual thread is stopped,
    // as io_thread_.global_ cleanup happens in CleanUp on the IO
    // thread, i.e. as the thread exits its message loop.
    //
    // This is important also because in various places, the
    // IOThread object being NULL is considered synonymous with the
    // IO thread having stopped.
    io_thread_.reset();
  }
  
  #if defined(OS_WIN)
  // Send a QuitTask to the given MessageLoop when the (file) thread has processed
  // our (other) recent requests (to save preferences).
  // Change the boolean so that the receiving thread will know that we did indeed
  // send the QuitTask that terminated the message loop.
  static void PostQuit(MessageLoop* message_loop) {
    g_end_session_file_thread_has_completed = true;
    message_loop->PostTask(FROM_HERE, MessageLoop::QuitClosure());
  }
  #elif defined(USE_X11)
  static void Signal(base::WaitableEvent* event) {
    event->Signal();
  }
  #endif
  
  unsigned int BrowserProcessImpl::AddRefModule() {
    DCHECK(CalledOnValidThread());
  
    // CHECK(!IsShuttingDown());
    if (IsShuttingDown()) {
      // Copy the stacktrace which released the final reference onto our stack so
      // it will be available in the crash report for inspection.
      base::debug::StackTrace callstack = release_last_reference_callstack_;
      base::debug::Alias(&callstack);
      CHECK(false);
    }
  
    did_start_ = true;
    module_ref_count_++;
    return module_ref_count_;
  }
  
  unsigned int BrowserProcessImpl::ReleaseModule() {
    DCHECK(CalledOnValidThread());
    DCHECK_NE(0u, module_ref_count_);
    module_ref_count_--;
    if (0 == module_ref_count_) {
      release_last_reference_callstack_ = base::debug::StackTrace();
  
  #if defined(ENABLE_PRINTING)
      // Wait for the pending print jobs to finish. Don't do this later, since
      // this might cause a nested message loop to run, and we don't want pending
      // tasks to run once teardown has started.
      print_job_manager_->OnQuit();
      print_job_manager_.reset();
  #endif
  
      CHECK(MessageLoop::current()->is_running());
  
  #if defined(OS_MACOSX)
      MessageLoop::current()->PostTask(
          FROM_HERE,
          base::Bind(ChromeBrowserMainPartsMac::DidEndMainMessageLoop));
  #endif
      MessageLoop::current()->Quit();
    }
    return module_ref_count_;
  }
  
  void BrowserProcessImpl::EndSession() {
    // Mark all the profiles as clean.
    ProfileManager* pm = profile_manager();
    std::vector<Profile*> profiles(pm->GetLoadedProfiles());
    for (size_t i = 0; i < profiles.size(); ++i)
      profiles[i]->SetExitType(Profile::EXIT_SESSION_ENDED);
  
    // Tell the metrics service it was cleanly shutdown.
    MetricsService* metrics = g_browser_process->metrics_service();
    if (metrics && local_state()) {
      metrics->RecordStartOfSessionEnd();
  
      // MetricsService lazily writes to prefs, force it to write now.
      local_state()->CommitPendingWrite();
    }
  
    // http://crbug.com/125207
    base::ThreadRestrictions::ScopedAllowWait allow_wait;
  
    // We must write that the profile and metrics service shutdown cleanly,
    // otherwise on startup we'll think we crashed. So we block until done and
    // then proceed with normal shutdown.
  #if defined(USE_X11)
    //  Can't run a local loop on linux. Instead create a waitable event.
    scoped_ptr<base::WaitableEvent> done_writing(
        new base::WaitableEvent(false, false));
    BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
        base::Bind(Signal, done_writing.get()));
    // If all file writes haven't cleared in the timeout, leak the WaitableEvent
    // so that there's no race to reference it in Signal().
    if (!done_writing->TimedWait(
        base::TimeDelta::FromSeconds(kEndSessionTimeoutSeconds)))
      ignore_result(done_writing.release());
  
  #elif defined(OS_WIN)
    BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
        base::Bind(PostQuit, MessageLoop::current()));
    int quits_received = 0;
    do {
      MessageLoop::current()->Run();
      ++quits_received;
    } while (!g_end_session_file_thread_has_completed);
    // If we did get extra quits, then we should re-post them to the message loop.
    while (--quits_received > 0)
      MessageLoop::current()->PostTask(FROM_HERE, MessageLoop::QuitClosure());
  #else
    NOTIMPLEMENTED();
  #endif
  }
  
  MetricsService* BrowserProcessImpl::metrics_service() {
    DCHECK(CalledOnValidThread());
    if (!created_metrics_service_)
      CreateMetricsService();
    return metrics_service_.get();
  }
  
  IOThread* BrowserProcessImpl::io_thread() {
    DCHECK(CalledOnValidThread());
    DCHECK(io_thread_.get());
    return io_thread_.get();
  }
  
  WatchDogThread* BrowserProcessImpl::watchdog_thread() {
    DCHECK(CalledOnValidThread());
    if (!created_watchdog_thread_)
      CreateWatchdogThread();
    DCHECK(watchdog_thread_.get() != NULL);
    return watchdog_thread_.get();
  }
  
  ProfileManager* BrowserProcessImpl::profile_manager() {
    DCHECK(CalledOnValidThread());
    if (!created_profile_manager_)
      CreateProfileManager();
    return profile_manager_.get();
  }
  
  PrefService* BrowserProcessImpl::local_state() {
    DCHECK(CalledOnValidThread());
    if (!created_local_state_)
      CreateLocalState();
    return local_state_.get();
  }
  
  net::URLRequestContextGetter* BrowserProcessImpl::system_request_context() {
    DCHECK(CalledOnValidThread());
    return io_thread()->system_url_request_context_getter();
  }
  
  chrome_variations::VariationsService* BrowserProcessImpl::variations_service() {
    DCHECK(CalledOnValidThread());
    if (!variations_service_.get())
      variations_service_.reset(new chrome_variations::VariationsService());
    return variations_service_.get();
  }
  
  #if defined(OS_CHROMEOS)
  chromeos::OomPriorityManager* BrowserProcessImpl::oom_priority_manager() {
    DCHECK(CalledOnValidThread());
    if (!oom_priority_manager_.get())
      oom_priority_manager_.reset(new chromeos::OomPriorityManager());
    return oom_priority_manager_.get();
  }
  #endif  // defined(OS_CHROMEOS)
  
  extensions::EventRouterForwarder*
  BrowserProcessImpl::extension_event_router_forwarder() {
    return extension_event_router_forwarder_.get();
  }
  
  NotificationUIManager* BrowserProcessImpl::notification_ui_manager() {
    DCHECK(CalledOnValidThread());
    if (!created_notification_ui_manager_)
      CreateNotificationUIManager();
    return notification_ui_manager_.get();
  }
  
  policy::BrowserPolicyConnector* BrowserProcessImpl::browser_policy_connector() {
    DCHECK(CalledOnValidThread());
  #if defined(ENABLE_CONFIGURATION_POLICY)
    if (!created_browser_policy_connector_) {
      // Init() should not reenter this function. If it does this will DCHECK.
      DCHECK(!browser_policy_connector_);
      browser_policy_connector_.reset(new policy::BrowserPolicyConnector());
      browser_policy_connector_->Init();
      created_browser_policy_connector_ = true;
    }
    return browser_policy_connector_.get();
  #else
    return NULL;
  #endif
  }
  
  policy::PolicyService* BrowserProcessImpl::policy_service() {
  #if defined(ENABLE_CONFIGURATION_POLICY)
    return browser_policy_connector()->GetPolicyService();
  #else
    if (!policy_service_.get())
      policy_service_.reset(new policy::PolicyServiceStub());
    return policy_service_.get();
  #endif
  }
  
  IconManager* BrowserProcessImpl::icon_manager() {
    DCHECK(CalledOnValidThread());
    if (!created_icon_manager_)
      CreateIconManager();
    return icon_manager_.get();
  }
  
  RenderWidgetSnapshotTaker* BrowserProcessImpl::GetRenderWidgetSnapshotTaker() {
    return render_widget_snapshot_taker_.get();
  }
  
  AutomationProviderList* BrowserProcessImpl::GetAutomationProviderList() {
    DCHECK(CalledOnValidThread());
  #if defined(ENABLE_AUTOMATION)
    if (automation_provider_list_.get() == NULL)
      automation_provider_list_.reset(new AutomationProviderList());
    return automation_provider_list_.get();
  #else
    return NULL;
  #endif
  }
  
  void BrowserProcessImpl::CreateDevToolsHttpProtocolHandler(
      Profile* profile,
      const std::string& ip,
      int port,
      const std::string& frontend_url) {
    DCHECK(CalledOnValidThread());
  #if !defined(OS_ANDROID)
    // StartupBrowserCreator::LaunchBrowser can be run multiple times when browser
    // is started with several profiles or existing browser process is reused.
    if (!remote_debugging_server_.get()) {
      remote_debugging_server_.reset(
          new RemoteDebuggingServer(profile, ip, port, frontend_url));
    }
  #endif
  }
  
  bool BrowserProcessImpl::IsShuttingDown() {
    DCHECK(CalledOnValidThread());
    return did_start_ && 0 == module_ref_count_;
  }
  
  printing::PrintJobManager* BrowserProcessImpl::print_job_manager() {
    // TODO(abarth): DCHECK(CalledOnValidThread());
    // http://code.google.com/p/chromium/issues/detail?id=6828
    // print_job_manager_ is initialized in the constructor and destroyed in the
    // destructor, so it should always be valid.
    DCHECK(print_job_manager_.get());
    return print_job_manager_.get();
  }
  
  printing::PrintPreviewTabController*
      BrowserProcessImpl::print_preview_tab_controller() {
  #if defined(ENABLE_PRINTING)
    DCHECK(CalledOnValidThread());
    if (!print_preview_tab_controller_.get())
      CreatePrintPreviewTabController();
    return print_preview_tab_controller_.get();
  #else
    NOTIMPLEMENTED();
    return NULL;
  #endif
  }
  
  printing::BackgroundPrintingManager*
      BrowserProcessImpl::background_printing_manager() {
  #if defined(ENABLE_PRINTING)
    DCHECK(CalledOnValidThread());
    if (!background_printing_manager_.get())
      CreateBackgroundPrintingManager();
    return background_printing_manager_.get();
  #else
    NOTIMPLEMENTED();
    return NULL;
  #endif
  }
  
  IntranetRedirectDetector* BrowserProcessImpl::intranet_redirect_detector() {
    DCHECK(CalledOnValidThread());
    if (!intranet_redirect_detector_.get())
      CreateIntranetRedirectDetector();
    return intranet_redirect_detector_.get();
  }
  
  const std::string& BrowserProcessImpl::GetApplicationLocale() {
    DCHECK(!locale_.empty());
    return locale_;
  }
  
  void BrowserProcessImpl::SetApplicationLocale(const std::string& locale) {
    locale_ = locale;
    extension_l10n_util::SetProcessLocale(locale);
    static_cast<chrome::ChromeContentBrowserClient*>(
        content::GetContentClient()->browser())->SetApplicationLocale(locale);
  }
  
  DownloadStatusUpdater* BrowserProcessImpl::download_status_updater() {
    return download_status_updater_.get();
  }
  
  DownloadRequestLimiter* BrowserProcessImpl::download_request_limiter() {
    DCHECK(CalledOnValidThread());
    if (!download_request_limiter_)
      download_request_limiter_ = new DownloadRequestLimiter();
    return download_request_limiter_;
  }
  
  BackgroundModeManager* BrowserProcessImpl::background_mode_manager() {
    DCHECK(CalledOnValidThread());
  #if defined(ENABLE_BACKGROUND)
    if (!background_mode_manager_.get())
      CreateBackgroundModeManager();
    return background_mode_manager_.get();
  #else
    NOTIMPLEMENTED();
    return NULL;
  #endif
  }
  
  StatusTray* BrowserProcessImpl::status_tray() {
    DCHECK(CalledOnValidThread());
    if (!status_tray_.get())
      CreateStatusTray();
    return status_tray_.get();
  }
  
  
  SafeBrowsingService* BrowserProcessImpl::safe_browsing_service() {
    DCHECK(CalledOnValidThread());
    if (!created_safe_browsing_service_)
      CreateSafeBrowsingService();
    return safe_browsing_service_.get();
  }
  
  safe_browsing::ClientSideDetectionService*
      BrowserProcessImpl::safe_browsing_detection_service() {
    DCHECK(CalledOnValidThread());
    if (safe_browsing_service())
      return safe_browsing_service()->safe_browsing_detection_service();
    return NULL;
  }
  
  bool BrowserProcessImpl::plugin_finder_disabled() const {
    if (plugin_finder_disabled_pref_.get())
      return plugin_finder_disabled_pref_->GetValue();
    else
      return false;
  }
  
  void BrowserProcessImpl::Observe(int type,
                                   const content::NotificationSource& source,
                                   const content::NotificationDetails& details) {
    if (type == chrome::NOTIFICATION_PREF_CHANGED) {
      std::string* pref = content::Details<std::string>(details).ptr();
      if (*pref == prefs::kDefaultBrowserSettingEnabled) {
        ApplyDefaultBrowserPolicy();
      } else if (*pref == prefs::kDisabledSchemes) {
        ApplyDisabledSchemesPolicy();
      } else if (*pref == prefs::kAllowCrossOriginAuthPrompt) {
        ApplyAllowCrossOriginAuthPromptPolicy();
      }
    } else {
      NOTREACHED();
    }
  }
  
  #if (defined(OS_WIN) || defined(OS_LINUX)) && !defined(OS_CHROMEOS)
  void BrowserProcessImpl::StartAutoupdateTimer() {
    autoupdate_timer_.Start(FROM_HERE,
        base::TimeDelta::FromHours(kUpdateCheckIntervalHours),
        this,
        &BrowserProcessImpl::OnAutoupdateTimer);
  }
  #endif
  
  ChromeNetLog* BrowserProcessImpl::net_log() {
    return net_log_.get();
  }
  
  prerender::PrerenderTracker* BrowserProcessImpl::prerender_tracker() {
    if (!prerender_tracker_.get())
      prerender_tracker_.reset(new prerender::PrerenderTracker);
  
    return prerender_tracker_.get();
  }
  
  ComponentUpdateService* BrowserProcessImpl::component_updater() {
  #if defined(OS_CHROMEOS)
    return NULL;
  #else
    if (!component_updater_.get()) {
      ComponentUpdateService::Configurator* configurator =
          MakeChromeComponentUpdaterConfigurator(
              CommandLine::ForCurrentProcess(),
              io_thread()->system_url_request_context_getter());
      // Creating the component updater does not do anything, components
      // need to be registered and Start() needs to be called.
      component_updater_.reset(ComponentUpdateServiceFactory(configurator));
    }
    return component_updater_.get();
  #endif
  }
  
  CRLSetFetcher* BrowserProcessImpl::crl_set_fetcher() {
  #if defined(OS_CHROMEOS)
    // There's no component updater on ChromeOS so there can't be a CRLSetFetcher
    // either.
    return NULL;
  #else
    if (!crl_set_fetcher_.get()) {
      crl_set_fetcher_ = new CRLSetFetcher();
    }
    return crl_set_fetcher_.get();
  #endif
  }
  
  void BrowserProcessImpl::ResourceDispatcherHostCreated() {
    resource_dispatcher_host_delegate_.reset(
        new ChromeResourceDispatcherHostDelegate(prerender_tracker()));
    ResourceDispatcherHost::Get()->SetDelegate(
        resource_dispatcher_host_delegate_.get());
  
    pref_change_registrar_.Add(prefs::kAllowCrossOriginAuthPrompt, this);
    ApplyAllowCrossOriginAuthPromptPolicy();
  }
  
  void BrowserProcessImpl::CreateMetricsService() {
    DCHECK(!created_metrics_service_ && metrics_service_.get() == NULL);
    created_metrics_service_ = true;
  
    metrics_service_.reset(new MetricsService);
  }
  
  void BrowserProcessImpl::CreateWatchdogThread() {
    DCHECK(!created_watchdog_thread_ && watchdog_thread_.get() == NULL);
    created_watchdog_thread_ = true;
  
    scoped_ptr<WatchDogThread> thread(new WatchDogThread());
    if (!thread->Start())
      return;
    watchdog_thread_.swap(thread);
  }
  
  void BrowserProcessImpl::CreateProfileManager() {
    DCHECK(!created_profile_manager_ && profile_manager_.get() == NULL);
    created_profile_manager_ = true;
  
    FilePath user_data_dir;
    PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
    profile_manager_.reset(new ProfileManager(user_data_dir));
  }
  
  void BrowserProcessImpl::CreateLocalState() {
    DCHECK(!created_local_state_ && local_state_.get() == NULL);
    created_local_state_ = true;
  
    FilePath local_state_path;
    PathService::Get(chrome::FILE_LOCAL_STATE, &local_state_path);
    local_state_.reset(
        PrefService::CreatePrefService(local_state_path, policy_service(), NULL,
                                       false));
  
    // Initialize the prefs of the local state.
    chrome::RegisterLocalState(local_state_.get());
  
    pref_change_registrar_.Init(local_state_.get());
  
    // Initialize the notification for the default browser setting policy.
    local_state_->RegisterBooleanPref(prefs::kDefaultBrowserSettingEnabled,
                                      false);
    pref_change_registrar_.Add(prefs::kDefaultBrowserSettingEnabled, this);
  
    // Initialize the preference for the plugin finder policy.
    // This preference is only needed on the IO thread so make it available there.
    local_state_->RegisterBooleanPref(prefs::kDisablePluginFinder, false);
    plugin_finder_disabled_pref_.reset(new BooleanPrefMember);
    plugin_finder_disabled_pref_->Init(prefs::kDisablePluginFinder,
                                     local_state_.get(), NULL);
    plugin_finder_disabled_pref_->MoveToThread(
        BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO));
  
    // Another policy that needs to be defined before the net subsystem is
    // initialized is MaxConnectionsPerProxy so we do it here.
    local_state_->RegisterIntegerPref(prefs::kMaxConnectionsPerProxy,
                                      net::kDefaultMaxSocketsPerProxyServer);
    int max_per_proxy = local_state_->GetInteger(prefs::kMaxConnectionsPerProxy);
    net::ClientSocketPoolManager::set_max_sockets_per_proxy_server(
        net::HttpNetworkSession::NORMAL_SOCKET_POOL,
        std::max(std::min(max_per_proxy, 99),
                 net::ClientSocketPoolManager::max_sockets_per_group(
                     net::HttpNetworkSession::NORMAL_SOCKET_POOL)));
  
    // This is observed by ChildProcessSecurityPolicy, which lives in content/
    // though, so it can't register itself.
    local_state_->RegisterListPref(prefs::kDisabledSchemes);
    pref_change_registrar_.Add(prefs::kDisabledSchemes, this);
    ApplyDisabledSchemesPolicy();
  
    local_state_->RegisterBooleanPref(prefs::kAllowCrossOriginAuthPrompt, false);
  
  #if defined(OS_WIN)
    if (base::win::GetVersion() >= base::win::VERSION_WIN8)
      local_state_->RegisterBooleanPref(prefs::kRestartSwitchMode, false);
  #endif
  }
  
  void BrowserProcessImpl::PreCreateThreads() {
    io_thread_.reset(new IOThread(
        local_state(), net_log_.get(), extension_event_router_forwarder_.get()));
  }
  
  void BrowserProcessImpl::PreMainMessageLoopRun() {
    PluginService* plugin_service = PluginService::GetInstance();
    plugin_service->SetFilter(ChromePluginServiceFilter::GetInstance());
    plugin_service->StartWatchingPlugins();
  
    // Register the internal Flash if available.
    FilePath path;
    if (!CommandLine::ForCurrentProcess()->HasSwitch(
            switches::kDisableInternalFlash) &&
        PathService::Get(chrome::FILE_FLASH_PLUGIN_EXISTING, &path)) {
      plugin_service->AddExtraPluginPath(path);
    }
  
    // Register bundled Pepper Flash if available.
    content::PepperPluginInfo plugin;
    bool add_at_beginning = false;
    chrome::ChromeContentClient* content_client =
        static_cast<chrome::ChromeContentClient*>(content::GetContentClient());
    if (content_client->GetBundledFieldTrialPepperFlash(&plugin,
                                                        &add_at_beginning)) {
      plugin_service->RegisterInternalPlugin(plugin.ToWebPluginInfo(),
                                             add_at_beginning);
    }
  
  #if defined(OS_POSIX)
    // Also find plugins in a user-specific plugins dir,
    // e.g. ~/.config/chromium/Plugins.
    FilePath user_data_dir;
    if (PathService::Get(chrome::DIR_USER_DATA, &user_data_dir)) {
      plugin_service->AddExtraPluginDir(user_data_dir.Append("Plugins"));
    }
  #endif
  
    if (local_state_->IsManagedPreference(prefs::kDefaultBrowserSettingEnabled))
      ApplyDefaultBrowserPolicy();
  
    // Triggers initialization of the singleton instance on UI thread.
    PluginFinder::GetInstance()->Init();
  
  #if defined(ENABLE_PLUGIN_INSTALLATION)
    if (!plugins_resource_service_) {
      plugins_resource_service_ = new PluginsResourceService(local_state());
      plugins_resource_service_->StartAfterDelay();
    }
  #endif
  }
  
  void BrowserProcessImpl::CreateIconManager() {
    DCHECK(!created_icon_manager_ && icon_manager_.get() == NULL);
    created_icon_manager_ = true;
    icon_manager_.reset(new IconManager);
  }
  
  void BrowserProcessImpl::CreateIntranetRedirectDetector() {
    DCHECK(intranet_redirect_detector_.get() == NULL);
    scoped_ptr<IntranetRedirectDetector> intranet_redirect_detector(
        new IntranetRedirectDetector);
    intranet_redirect_detector_.swap(intranet_redirect_detector);
  }
  
  void BrowserProcessImpl::CreateNotificationUIManager() {
  #if defined(ENABLE_NOTIFICATIONS)
    DCHECK(notification_ui_manager_.get() == NULL);
    notification_ui_manager_.reset(NotificationUIManager::Create(local_state()));
    created_notification_ui_manager_ = true;
  #endif
  }
  
  void BrowserProcessImpl::CreateBackgroundModeManager() {
    DCHECK(background_mode_manager_.get() == NULL);
    background_mode_manager_.reset(
        new BackgroundModeManager(CommandLine::ForCurrentProcess(),
                                  &profile_manager()->GetProfileInfoCache()));
  }
  
  void BrowserProcessImpl::CreateStatusTray() {
    DCHECK(status_tray_.get() == NULL);
    status_tray_.reset(StatusTray::Create());
  }
  
  void BrowserProcessImpl::CreatePrintPreviewTabController() {
  #if defined(ENABLE_PRINTING)
    DCHECK(print_preview_tab_controller_.get() == NULL);
    print_preview_tab_controller_ = new printing::PrintPreviewTabController();
  #else
    NOTIMPLEMENTED();
  #endif
  }
  
  void BrowserProcessImpl::CreateBackgroundPrintingManager() {
  #if defined(ENABLE_PRINTING)
    DCHECK(background_printing_manager_.get() == NULL);
    background_printing_manager_.reset(new printing::BackgroundPrintingManager());
  #else
    NOTIMPLEMENTED();
  #endif
  }
  
  void BrowserProcessImpl::CreateSafeBrowsingService() {
    DCHECK(safe_browsing_service_.get() == NULL);
    // Set this flag to true so that we don't retry indefinitely to
    // create the service class if there was an error.
    created_safe_browsing_service_ = true;
  #if defined(ENABLE_SAFE_BROWSING)
    safe_browsing_service_ = SafeBrowsingService::CreateSafeBrowsingService();
    safe_browsing_service_->Initialize();
  #endif
  }
  
  void BrowserProcessImpl::ApplyDisabledSchemesPolicy() {
    std::set<std::string> schemes;
    const ListValue* scheme_list = local_state_->GetList(prefs::kDisabledSchemes);
    for (ListValue::const_iterator iter = scheme_list->begin();
         iter != scheme_list->end(); ++iter) {
      std::string scheme;
      if ((*iter)->GetAsString(&scheme))
        schemes.insert(scheme);
    }
    ChildProcessSecurityPolicy::GetInstance()->RegisterDisabledSchemes(schemes);
  }
  
  void BrowserProcessImpl::ApplyDefaultBrowserPolicy() {
    if (local_state_->GetBoolean(prefs::kDefaultBrowserSettingEnabled)) {
      scoped_refptr<ShellIntegration::DefaultWebClientWorker>
          set_browser_worker = new ShellIntegration::DefaultBrowserWorker(NULL);
      set_browser_worker->StartSetAsDefault();
    }
  }
  
  void BrowserProcessImpl::ApplyAllowCrossOriginAuthPromptPolicy() {
    bool value = local_state()->GetBoolean(prefs::kAllowCrossOriginAuthPrompt);
    ResourceDispatcherHost::Get()->SetAllowCrossOriginAuthPrompt(value);
  }
  
  // Mac is currently not supported.
  #if (defined(OS_WIN) || defined(OS_LINUX)) && !defined(OS_CHROMEOS)
  
  bool BrowserProcessImpl::CanAutorestartForUpdate() const {
    // Check if browser is in the background and if it needs to be restarted to
    // apply a pending update.
    return BrowserList::size() == 0 && browser::WillKeepAlive() &&
           upgrade_util::IsUpdatePendingRestart();
  }
  
  // Switches to add when auto-restarting Chrome.
  const char* const kSwitchesToAddOnAutorestart[] = {
    switches::kNoStartupWindow
  };
  
  void BrowserProcessImpl::RestartBackgroundInstance() {
    CommandLine* old_cl = CommandLine::ForCurrentProcess();
    scoped_ptr<CommandLine> new_cl(new CommandLine(old_cl->GetProgram()));
  
    std::map<std::string, CommandLine::StringType> switches =
        old_cl->GetSwitches();
  
    switches::RemoveSwitchesForAutostart(&switches);
  
    // Append the rest of the switches (along with their values, if any)
    // to the new command line
    for (std::map<std::string, CommandLine::StringType>::const_iterator i =
        switches.begin(); i != switches.end(); ++i) {
        CommandLine::StringType switch_value = i->second;
        if (switch_value.length() > 0) {
          new_cl->AppendSwitchNative(i->first, i->second);
        } else {
          new_cl->AppendSwitch(i->first);
        }
    }
  
    // Ensure that our desired switches are set on the new process.
    for (size_t i = 0; i < arraysize(kSwitchesToAddOnAutorestart); ++i) {
      if (!new_cl->HasSwitch(kSwitchesToAddOnAutorestart[i]))
        new_cl->AppendSwitch(kSwitchesToAddOnAutorestart[i]);
    }
  
    DLOG(WARNING) << "Shutting down current instance of the browser.";
    browser::AttemptExit();
  
    // Transfer ownership to Upgrade.
    upgrade_util::SetNewCommandLine(new_cl.release());
  }
  
  void BrowserProcessImpl::OnAutoupdateTimer() {
    if (CanAutorestartForUpdate()) {
      DLOG(WARNING) << "Detected update.  Restarting browser.";
      RestartBackgroundInstance();
    }
  }
  
  #endif  // (defined(OS_WIN) || defined(OS_LINUX)) && !defined(OS_CHROMEOS)
  