browser_process_impl.cc revision 3345a6884c488ff3a535c2c9acdd33d74b37e311
1// Copyright (c) 2010 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/browser_process_impl.h"
6
7#include <map>
8
9#include "app/clipboard/clipboard.h"
10#include "app/l10n_util.h"
11#include "base/command_line.h"
12#include "base/file_util.h"
13#include "base/path_service.h"
14#include "base/task.h"
15#include "base/thread.h"
16#include "base/waitable_event.h"
17#include "chrome/browser/appcache/chrome_appcache_service.h"
18#include "chrome/browser/automation/automation_provider_list.h"
19#include "chrome/browser/browser_child_process_host.h"
20#include "chrome/browser/browser_list.h"
21#include "chrome/browser/browser_main.h"
22#include "chrome/browser/browser_process_sub_thread.h"
23#include "chrome/browser/browser_trial.h"
24#include "chrome/browser/chrome_thread.h"
25#include "chrome/browser/debugger/debugger_wrapper.h"
26#include "chrome/browser/debugger/devtools_manager.h"
27#include "chrome/browser/download/download_file_manager.h"
28#include "chrome/browser/download/save_file_manager.h"
29#include "chrome/browser/first_run/first_run.h"
30#include "chrome/browser/google/google_url_tracker.h"
31#include "chrome/browser/icon_manager.h"
32#include "chrome/browser/in_process_webkit/dom_storage_context.h"
33#include "chrome/browser/intranet_redirect_detector.h"
34#include "chrome/browser/io_thread.h"
35#include "chrome/browser/metrics/metrics_service.h"
36#include "chrome/browser/net/predictor_api.h"
37#include "chrome/browser/net/sdch_dictionary_fetcher.h"
38#include "chrome/browser/net/sqlite_persistent_cookie_store.h"
39#include "chrome/browser/notifications/notification_ui_manager.h"
40#include "chrome/browser/plugin_service.h"
41#include "chrome/browser/plugin_updater.h"
42#include "chrome/browser/prefs/pref_service.h"
43#include "chrome/browser/printing/print_job_manager.h"
44#include "chrome/browser/profile_manager.h"
45#include "chrome/browser/renderer_host/render_process_host.h"
46#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
47#include "chrome/browser/safe_browsing/safe_browsing_service.h"
48#include "chrome/browser/sidebar/sidebar_manager.h"
49#include "chrome/browser/tab_closeable_state_watcher.h"
50#include "chrome/common/chrome_constants.h"
51#include "chrome/common/chrome_paths.h"
52#include "chrome/common/chrome_switches.h"
53#include "chrome/common/extensions/extension_resource.h"
54#include "chrome/common/extensions/extension_l10n_util.h"
55#include "chrome/common/json_pref_store.h"
56#include "chrome/common/notification_service.h"
57#include "chrome/common/pref_names.h"
58#include "chrome/common/url_constants.h"
59#include "chrome/common/switch_utils.h"
60#include "chrome/installer/util/google_update_constants.h"
61#include "ipc/ipc_logging.h"
62#include "webkit/database/database_tracker.h"
63
64#if defined(OS_WIN)
65#include "views/focus/view_storage.h"
66#endif
67
68#if defined(IPC_MESSAGE_LOG_ENABLED)
69#include "chrome/common/plugin_messages.h"
70#include "chrome/common/render_messages.h"
71#endif
72
73#if (defined(OS_WIN) || defined(OS_LINUX)) && !defined(OS_CHROMEOS)
74// How often to check if the persistent instance of Chrome needs to restart
75// to install an update.
76static const int kUpdateCheckIntervalHours = 6;
77#endif
78
79#if defined(USE_X11)
80// How long to wait for the File thread to complete during EndSession, on
81// Linux. We have a timeout here because we're unable to run the UI messageloop
82// and there's some deadlock risk. Our only option is to exit anyway.
83static const int kEndSessionTimeoutSeconds = 10;
84#endif
85
86BrowserProcessImpl::BrowserProcessImpl(const CommandLine& command_line)
87    : created_resource_dispatcher_host_(false),
88      created_metrics_service_(false),
89      created_io_thread_(false),
90      created_file_thread_(false),
91      created_db_thread_(false),
92      created_process_launcher_thread_(false),
93      created_cache_thread_(false),
94      created_profile_manager_(false),
95      created_local_state_(false),
96      created_icon_manager_(false),
97      created_debugger_wrapper_(false),
98      created_devtools_manager_(false),
99      created_sidebar_manager_(false),
100      created_notification_ui_manager_(false),
101      module_ref_count_(0),
102      did_start_(false),
103      checked_for_new_frames_(false),
104      using_new_frames_(false),
105      have_inspector_files_(true) {
106  g_browser_process = this;
107  clipboard_.reset(new Clipboard);
108  main_notification_service_.reset(new NotificationService);
109
110  // Must be created after the NotificationService.
111  print_job_manager_.reset(new printing::PrintJobManager);
112
113  shutdown_event_.reset(new base::WaitableEvent(true, false));
114}
115
116BrowserProcessImpl::~BrowserProcessImpl() {
117  FilePath profile_path;
118  bool clear_local_state_on_exit;
119
120  // Store the profile path for clearing local state data on exit.
121  clear_local_state_on_exit = ShouldClearLocalState(&profile_path);
122
123  // Delete the AutomationProviderList before NotificationService,
124  // since it may try to unregister notifications
125  // Both NotificationService and AutomationProvider are singleton instances in
126  // the BrowserProcess. Since AutomationProvider may have some active
127  // notification observers, it is essential that it gets destroyed before the
128  // NotificationService. NotificationService won't be destroyed until after
129  // this destructor is run.
130  automation_provider_list_.reset();
131
132  // We need to shutdown the SdchDictionaryFetcher as it regularly holds
133  // a pointer to a URLFetcher, and that URLFetcher (upon destruction) will do
134  // a PostDelayedTask onto the IO thread.  This shutdown call will both discard
135  // any pending URLFetchers, and avoid creating any more.
136  SdchDictionaryFetcher::Shutdown();
137
138  // We need to destroy the MetricsService, GoogleURLTracker, and
139  // IntranetRedirectDetector before the io_thread_ gets destroyed, since their
140  // destructors can call the URLFetcher destructor, which does a
141  // PostDelayedTask operation on the IO thread.  (The IO thread will handle
142  // that URLFetcher operation before going away.)
143  metrics_service_.reset();
144  google_url_tracker_.reset();
145  intranet_redirect_detector_.reset();
146
147  // Need to clear the desktop notification balloons before the io_thread_ and
148  // before the profiles, since if there are any still showing we will access
149  // those things during teardown.
150  notification_ui_manager_.reset();
151
152  // Need to clear profiles (download managers) before the io_thread_.
153  profile_manager_.reset();
154
155  // Debugger must be cleaned up before IO thread and NotificationService.
156  debugger_wrapper_ = NULL;
157
158  if (resource_dispatcher_host_.get()) {
159    // Need to tell Safe Browsing Service that the IO thread is going away
160    // since it cached a pointer to it.
161    if (resource_dispatcher_host()->safe_browsing_service())
162      resource_dispatcher_host()->safe_browsing_service()->ShutDown();
163
164    // Cancel pending requests and prevent new requests.
165    resource_dispatcher_host()->Shutdown();
166  }
167
168#if defined(USE_X11)
169  // The IO thread must outlive the BACKGROUND_X11 thread.
170  background_x11_thread_.reset();
171#endif
172
173  // Need to stop io_thread_ before resource_dispatcher_host_, since
174  // io_thread_ may still deref ResourceDispatcherHost and handle resource
175  // request before going away.
176  io_thread_.reset();
177
178  // The IO thread was the only user of this thread.
179  cache_thread_.reset();
180
181  // Stop the process launcher thread after the IO thread, in case the IO thread
182  // posted a task to terminate a process on the process launcher thread.
183  process_launcher_thread_.reset();
184
185  // Clean up state that lives on the file_thread_ before it goes away.
186  if (resource_dispatcher_host_.get()) {
187    resource_dispatcher_host()->download_file_manager()->Shutdown();
188    resource_dispatcher_host()->save_file_manager()->Shutdown();
189  }
190
191  // Need to stop the file_thread_ here to force it to process messages in its
192  // message loop from the previous call to shutdown the DownloadFileManager,
193  // SaveFileManager and SessionService.
194  file_thread_.reset();
195
196  // With the file_thread_ flushed, we can release any icon resources.
197  icon_manager_.reset();
198
199  // Need to destroy ResourceDispatcherHost before PluginService and
200  // SafeBrowsingService, since it caches a pointer to it. This also
201  // causes the webkit thread to terminate.
202  resource_dispatcher_host_.reset();
203
204  // Wait for the pending print jobs to finish.
205  print_job_manager_->OnQuit();
206  print_job_manager_.reset();
207
208  // Destroy TabCloseableStateWatcher before NotificationService since the
209  // former registers for notifications.
210  tab_closeable_state_watcher_.reset();
211
212  // Now OK to destroy NotificationService.
213  main_notification_service_.reset();
214
215  // Prior to clearing local state, we want to complete tasks pending
216  // on the db thread too.
217  db_thread_.reset();
218
219  // At this point, no render process exist and the file, io, db, and
220  // webkit threads in this process have all terminated, so it's safe
221  // to access local state data such as cookies, database, or local storage.
222  if (clear_local_state_on_exit)
223    ClearLocalState(profile_path);
224
225  g_browser_process = NULL;
226}
227
228#if defined(OS_WIN)
229// Send a QuitTask to the given MessageLoop.
230static void PostQuit(MessageLoop* message_loop) {
231  message_loop->PostTask(FROM_HERE, new MessageLoop::QuitTask());
232}
233#elif defined(USE_X11)
234static void Signal(base::WaitableEvent* event) {
235  event->Signal();
236}
237#endif
238
239unsigned int BrowserProcessImpl::AddRefModule() {
240  DCHECK(CalledOnValidThread());
241  did_start_ = true;
242  module_ref_count_++;
243  return module_ref_count_;
244}
245
246unsigned int BrowserProcessImpl::ReleaseModule() {
247  DCHECK(CalledOnValidThread());
248  DCHECK_NE(0u, module_ref_count_);
249  module_ref_count_--;
250  if (0 == module_ref_count_) {
251    MessageLoop::current()->PostTask(
252        FROM_HERE, NewRunnableFunction(DidEndMainMessageLoop));
253    MessageLoop::current()->Quit();
254  }
255  return module_ref_count_;
256}
257
258void BrowserProcessImpl::EndSession() {
259#if defined(OS_WIN) || defined(USE_X11)
260  // Notify we are going away.
261  shutdown_event_->Signal();
262#endif
263
264  // Mark all the profiles as clean.
265  ProfileManager* pm = profile_manager();
266  for (ProfileManager::const_iterator i = pm->begin(); i != pm->end(); ++i)
267    (*i)->MarkAsCleanShutdown();
268
269  // Tell the metrics service it was cleanly shutdown.
270  MetricsService* metrics = g_browser_process->metrics_service();
271  if (metrics && local_state()) {
272    metrics->RecordCleanShutdown();
273
274    metrics->RecordStartOfSessionEnd();
275
276    // MetricsService lazily writes to prefs, force it to write now.
277    local_state()->SavePersistentPrefs();
278  }
279
280  // We must write that the profile and metrics service shutdown cleanly,
281  // otherwise on startup we'll think we crashed. So we block until done and
282  // then proceed with normal shutdown.
283#if defined(USE_X11)
284  //  Can't run a local loop on linux. Instead create a waitable event.
285  base::WaitableEvent done_writing(false, false);
286  ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE,
287      NewRunnableFunction(Signal, &done_writing));
288  done_writing.TimedWait(
289      base::TimeDelta::FromSeconds(kEndSessionTimeoutSeconds));
290#elif defined(OS_WIN)
291  ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE,
292      NewRunnableFunction(PostQuit, MessageLoop::current()));
293  MessageLoop::current()->Run();
294#else
295  NOTIMPLEMENTED();
296#endif
297}
298
299ResourceDispatcherHost* BrowserProcessImpl::resource_dispatcher_host() {
300  DCHECK(CalledOnValidThread());
301  if (!created_resource_dispatcher_host_)
302    CreateResourceDispatcherHost();
303  return resource_dispatcher_host_.get();
304}
305
306MetricsService* BrowserProcessImpl::metrics_service() {
307  DCHECK(CalledOnValidThread());
308  if (!created_metrics_service_)
309    CreateMetricsService();
310  return metrics_service_.get();
311}
312
313IOThread* BrowserProcessImpl::io_thread() {
314  DCHECK(CalledOnValidThread());
315  if (!created_io_thread_)
316    CreateIOThread();
317  return io_thread_.get();
318}
319
320base::Thread* BrowserProcessImpl::file_thread() {
321  DCHECK(CalledOnValidThread());
322  if (!created_file_thread_)
323    CreateFileThread();
324  return file_thread_.get();
325}
326
327base::Thread* BrowserProcessImpl::db_thread() {
328  DCHECK(CalledOnValidThread());
329  if (!created_db_thread_)
330    CreateDBThread();
331  return db_thread_.get();
332}
333
334base::Thread* BrowserProcessImpl::process_launcher_thread() {
335  DCHECK(CalledOnValidThread());
336  if (!created_process_launcher_thread_)
337    CreateProcessLauncherThread();
338  return process_launcher_thread_.get();
339}
340
341base::Thread* BrowserProcessImpl::cache_thread() {
342  DCHECK(CalledOnValidThread());
343  if (!created_cache_thread_)
344    CreateCacheThread();
345  return cache_thread_.get();
346}
347
348#if defined(USE_X11)
349base::Thread* BrowserProcessImpl::background_x11_thread() {
350  DCHECK(CalledOnValidThread());
351  // The BACKGROUND_X11 thread is created when the IO thread is created.
352  if (!created_io_thread_)
353    CreateIOThread();
354  return background_x11_thread_.get();
355}
356#endif
357
358ProfileManager* BrowserProcessImpl::profile_manager() {
359  DCHECK(CalledOnValidThread());
360  if (!created_profile_manager_)
361    CreateProfileManager();
362  return profile_manager_.get();
363}
364
365PrefService* BrowserProcessImpl::local_state() {
366  DCHECK(CalledOnValidThread());
367  if (!created_local_state_)
368    CreateLocalState();
369  return local_state_.get();
370}
371
372DevToolsManager* BrowserProcessImpl::devtools_manager() {
373  DCHECK(CalledOnValidThread());
374  if (!created_devtools_manager_)
375    CreateDevToolsManager();
376  return devtools_manager_.get();
377}
378
379SidebarManager* BrowserProcessImpl::sidebar_manager() {
380  DCHECK(CalledOnValidThread());
381  if (!created_sidebar_manager_)
382    CreateSidebarManager();
383  return sidebar_manager_.get();
384}
385
386Clipboard* BrowserProcessImpl::clipboard() {
387  DCHECK(CalledOnValidThread());
388  return clipboard_.get();
389}
390
391NotificationUIManager* BrowserProcessImpl::notification_ui_manager() {
392  DCHECK(CalledOnValidThread());
393  if (!created_notification_ui_manager_)
394    CreateNotificationUIManager();
395  return notification_ui_manager_.get();
396}
397
398IconManager* BrowserProcessImpl::icon_manager() {
399  DCHECK(CalledOnValidThread());
400  if (!created_icon_manager_)
401    CreateIconManager();
402  return icon_manager_.get();
403}
404
405ThumbnailGenerator* BrowserProcessImpl::GetThumbnailGenerator() {
406  return &thumbnail_generator_;
407}
408
409AutomationProviderList* BrowserProcessImpl::InitAutomationProviderList() {
410  DCHECK(CalledOnValidThread());
411  if (automation_provider_list_.get() == NULL) {
412    automation_provider_list_.reset(AutomationProviderList::GetInstance());
413  }
414  return automation_provider_list_.get();
415}
416
417void BrowserProcessImpl::InitDebuggerWrapper(int port, bool useHttp) {
418  DCHECK(CalledOnValidThread());
419  if (!created_debugger_wrapper_)
420    CreateDebuggerWrapper(port, useHttp);
421}
422
423bool BrowserProcessImpl::IsShuttingDown() {
424  DCHECK(CalledOnValidThread());
425  return did_start_ && 0 == module_ref_count_;
426}
427
428printing::PrintJobManager* BrowserProcessImpl::print_job_manager() {
429  // TODO(abarth): DCHECK(CalledOnValidThread());
430  // http://code.google.com/p/chromium/issues/detail?id=6828
431  // print_job_manager_ is initialized in the constructor and destroyed in the
432  // destructor, so it should always be valid.
433  DCHECK(print_job_manager_.get());
434  return print_job_manager_.get();
435}
436
437GoogleURLTracker* BrowserProcessImpl::google_url_tracker() {
438  DCHECK(CalledOnValidThread());
439  if (!google_url_tracker_.get())
440    CreateGoogleURLTracker();
441  return google_url_tracker_.get();
442}
443
444IntranetRedirectDetector* BrowserProcessImpl::intranet_redirect_detector() {
445  DCHECK(CalledOnValidThread());
446  if (!intranet_redirect_detector_.get())
447    CreateIntranetRedirectDetector();
448  return intranet_redirect_detector_.get();
449}
450
451const std::string& BrowserProcessImpl::GetApplicationLocale() {
452  DCHECK(!locale_.empty());
453  return locale_;
454}
455
456void BrowserProcessImpl::SetApplicationLocale(const std::string& locale) {
457  locale_ = locale;
458  extension_l10n_util::SetProcessLocale(locale);
459}
460
461DownloadStatusUpdater* BrowserProcessImpl::download_status_updater() {
462  return &download_status_updater_;
463}
464
465base::WaitableEvent* BrowserProcessImpl::shutdown_event() {
466  return shutdown_event_.get();
467}
468
469TabCloseableStateWatcher* BrowserProcessImpl::tab_closeable_state_watcher() {
470  DCHECK(CalledOnValidThread());
471  if (!tab_closeable_state_watcher_.get())
472    CreateTabCloseableStateWatcher();
473  return tab_closeable_state_watcher_.get();
474}
475
476void BrowserProcessImpl::CheckForInspectorFiles() {
477  file_thread()->message_loop()->PostTask
478      (FROM_HERE,
479       NewRunnableMethod(this, &BrowserProcessImpl::DoInspectorFilesCheck));
480}
481
482#if (defined(OS_WIN) || defined(OS_LINUX)) && !defined(OS_CHROMEOS)
483void BrowserProcessImpl::StartAutoupdateTimer() {
484  autoupdate_timer_.Start(
485      base::TimeDelta::FromHours(kUpdateCheckIntervalHours),
486      this,
487      &BrowserProcessImpl::OnAutoupdateTimer);
488}
489#endif
490
491bool BrowserProcessImpl::have_inspector_files() const {
492  return have_inspector_files_;
493}
494
495void BrowserProcessImpl::ClearLocalState(const FilePath& profile_path) {
496  SQLitePersistentCookieStore::ClearLocalState(profile_path.Append(
497      chrome::kCookieFilename));
498  DOMStorageContext::ClearLocalState(profile_path, chrome::kExtensionScheme);
499  webkit_database::DatabaseTracker::ClearLocalState(profile_path);
500  ChromeAppCacheService::ClearLocalState(profile_path);
501}
502
503bool BrowserProcessImpl::ShouldClearLocalState(FilePath* profile_path) {
504  FilePath user_data_dir;
505  Profile* profile;
506
507  // Check for the existence of a profile manager. When quitting early,
508  // e.g. because another chrome instance is running, or when invoked with
509  // options such as --uninstall or --try-chrome-again=0, the profile manager
510  // does not exist yet.
511  if (!profile_manager_.get())
512    return false;
513
514  PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
515  profile = profile_manager_->GetDefaultProfile(user_data_dir);
516  if (!profile)
517    return false;
518  *profile_path = profile->GetPath();
519  return profile->GetPrefs()->GetBoolean(prefs::kClearSiteDataOnExit);
520}
521
522void BrowserProcessImpl::CreateResourceDispatcherHost() {
523  DCHECK(!created_resource_dispatcher_host_ &&
524         resource_dispatcher_host_.get() == NULL);
525  created_resource_dispatcher_host_ = true;
526
527  resource_dispatcher_host_.reset(new ResourceDispatcherHost());
528  resource_dispatcher_host_->Initialize();
529}
530
531void BrowserProcessImpl::CreateMetricsService() {
532  DCHECK(!created_metrics_service_ && metrics_service_.get() == NULL);
533  created_metrics_service_ = true;
534
535  metrics_service_.reset(new MetricsService);
536}
537
538void BrowserProcessImpl::CreateIOThread() {
539  DCHECK(!created_io_thread_ && io_thread_.get() == NULL);
540  created_io_thread_ = true;
541
542  // Prior to starting the io thread, we create the plugin service as
543  // it is predominantly used from the io thread, but must be created
544  // on the main thread. The service ctor is inexpensive and does not
545  // invoke the io_thread() accessor.
546  PluginService::GetInstance();
547
548#if defined(USE_X11)
549  // The lifetime of the BACKGROUND_X11 thread is a subset of the IO thread so
550  // we start it now.
551  scoped_ptr<base::Thread> background_x11_thread(
552      new BrowserProcessSubThread(ChromeThread::BACKGROUND_X11));
553  if (!background_x11_thread->Start())
554    return;
555  background_x11_thread_.swap(background_x11_thread);
556#endif
557
558  scoped_ptr<IOThread> thread(new IOThread);
559  base::Thread::Options options;
560  options.message_loop_type = MessageLoop::TYPE_IO;
561  if (!thread->StartWithOptions(options))
562    return;
563  io_thread_.swap(thread);
564}
565
566void BrowserProcessImpl::CreateFileThread() {
567  DCHECK(!created_file_thread_ && file_thread_.get() == NULL);
568  created_file_thread_ = true;
569
570  scoped_ptr<base::Thread> thread(
571      new BrowserProcessSubThread(ChromeThread::FILE));
572  base::Thread::Options options;
573#if defined(OS_WIN)
574  // On Windows, the FILE thread needs to be have a UI message loop which pumps
575  // messages in such a way that Google Update can communicate back to us.
576  options.message_loop_type = MessageLoop::TYPE_UI;
577#else
578  options.message_loop_type = MessageLoop::TYPE_IO;
579#endif
580  if (!thread->StartWithOptions(options))
581    return;
582  file_thread_.swap(thread);
583
584  // ExtensionResource is in chrome/common, so it cannot depend on
585  // chrome/browser, which means it cannot lookup what the File thread is.
586  // We therefore store the thread ID from here so we can validate the proper
587  // thread usage in the ExtensionResource class.
588  ExtensionResource::set_file_thread_id(file_thread_->thread_id());
589}
590
591void BrowserProcessImpl::CreateDBThread() {
592  DCHECK(!created_db_thread_ && db_thread_.get() == NULL);
593  created_db_thread_ = true;
594
595  scoped_ptr<base::Thread> thread(
596      new BrowserProcessSubThread(ChromeThread::DB));
597  if (!thread->Start())
598    return;
599  db_thread_.swap(thread);
600}
601
602void BrowserProcessImpl::CreateProcessLauncherThread() {
603  DCHECK(!created_process_launcher_thread_ && !process_launcher_thread_.get());
604  created_process_launcher_thread_ = true;
605
606  scoped_ptr<base::Thread> thread(
607      new BrowserProcessSubThread(ChromeThread::PROCESS_LAUNCHER));
608  if (!thread->Start())
609    return;
610  process_launcher_thread_.swap(thread);
611}
612
613void BrowserProcessImpl::CreateCacheThread() {
614  DCHECK(!created_cache_thread_ && !cache_thread_.get());
615  created_cache_thread_ = true;
616
617  scoped_ptr<base::Thread> thread(
618      new BrowserProcessSubThread(ChromeThread::CACHE));
619  base::Thread::Options options;
620  options.message_loop_type = MessageLoop::TYPE_IO;
621  if (!thread->StartWithOptions(options))
622    return;
623  cache_thread_.swap(thread);
624}
625
626void BrowserProcessImpl::CreateProfileManager() {
627  DCHECK(!created_profile_manager_ && profile_manager_.get() == NULL);
628  created_profile_manager_ = true;
629
630  profile_manager_.reset(new ProfileManager());
631}
632
633void BrowserProcessImpl::CreateLocalState() {
634  DCHECK(!created_local_state_ && local_state_.get() == NULL);
635  created_local_state_ = true;
636
637  FilePath local_state_path;
638  PathService::Get(chrome::FILE_LOCAL_STATE, &local_state_path);
639  local_state_.reset(PrefService::CreatePrefService(local_state_path, NULL));
640
641  // Make sure the the plugin updater gets notifications of changes
642  // in the plugin blacklist.
643  local_state_->RegisterListPref(prefs::kPluginsPluginsBlacklist);
644  plugin_state_change_registrar_.Init(local_state_.get());
645  plugin_state_change_registrar_.Add(prefs::kPluginsPluginsBlacklist,
646                                     PluginUpdater::GetPluginUpdater());
647}
648
649void BrowserProcessImpl::CreateIconManager() {
650  DCHECK(!created_icon_manager_ && icon_manager_.get() == NULL);
651  created_icon_manager_ = true;
652  icon_manager_.reset(new IconManager);
653}
654
655void BrowserProcessImpl::CreateDebuggerWrapper(int port, bool useHttp) {
656  DCHECK(debugger_wrapper_.get() == NULL);
657  created_debugger_wrapper_ = true;
658
659  debugger_wrapper_ = new DebuggerWrapper(port, useHttp);
660}
661
662void BrowserProcessImpl::CreateDevToolsManager() {
663  DCHECK(devtools_manager_.get() == NULL);
664  created_devtools_manager_ = true;
665  devtools_manager_ = new DevToolsManager();
666}
667
668void BrowserProcessImpl::CreateSidebarManager() {
669  DCHECK(sidebar_manager_.get() == NULL);
670  created_sidebar_manager_ = true;
671  sidebar_manager_ = new SidebarManager();
672}
673
674void BrowserProcessImpl::CreateGoogleURLTracker() {
675  DCHECK(google_url_tracker_.get() == NULL);
676  scoped_ptr<GoogleURLTracker> google_url_tracker(new GoogleURLTracker);
677  google_url_tracker_.swap(google_url_tracker);
678}
679
680void BrowserProcessImpl::CreateIntranetRedirectDetector() {
681  DCHECK(intranet_redirect_detector_.get() == NULL);
682  scoped_ptr<IntranetRedirectDetector> intranet_redirect_detector(
683      new IntranetRedirectDetector);
684  intranet_redirect_detector_.swap(intranet_redirect_detector);
685}
686
687void BrowserProcessImpl::CreateNotificationUIManager() {
688  DCHECK(notification_ui_manager_.get() == NULL);
689  notification_ui_manager_.reset(NotificationUIManager::Create());
690  created_notification_ui_manager_ = true;
691}
692
693void BrowserProcessImpl::CreateTabCloseableStateWatcher() {
694  DCHECK(tab_closeable_state_watcher_.get() == NULL);
695  tab_closeable_state_watcher_.reset(TabCloseableStateWatcher::Create());
696}
697
698// The BrowserProcess object must outlive the file thread so we use traits
699// which don't do any management.
700DISABLE_RUNNABLE_METHOD_REFCOUNT(BrowserProcessImpl);
701
702#if defined(IPC_MESSAGE_LOG_ENABLED)
703
704void BrowserProcessImpl::SetIPCLoggingEnabled(bool enable) {
705  // First enable myself.
706  if (enable)
707    IPC::Logging::current()->Enable();
708  else
709    IPC::Logging::current()->Disable();
710
711  // Now tell subprocesses.  Messages to ChildProcess-derived
712  // processes must be done on the IO thread.
713  io_thread()->message_loop()->PostTask
714      (FROM_HERE,
715       NewRunnableMethod(
716           this,
717           &BrowserProcessImpl::SetIPCLoggingEnabledForChildProcesses,
718           enable));
719
720  // Finally, tell the renderers which don't derive from ChildProcess.
721  // Messages to the renderers must be done on the UI (main) thread.
722  for (RenderProcessHost::iterator i(RenderProcessHost::AllHostsIterator());
723       !i.IsAtEnd(); i.Advance())
724    i.GetCurrentValue()->Send(new ViewMsg_SetIPCLoggingEnabled(enable));
725}
726
727// Helper for SetIPCLoggingEnabled.
728void BrowserProcessImpl::SetIPCLoggingEnabledForChildProcesses(bool enabled) {
729  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
730
731  BrowserChildProcessHost::Iterator i;  // default constr references a singleton
732  while (!i.Done()) {
733    i->Send(new PluginProcessMsg_SetIPCLoggingEnabled(enabled));
734    ++i;
735  }
736}
737
738#endif  // IPC_MESSAGE_LOG_ENABLED
739
740void BrowserProcessImpl::DoInspectorFilesCheck() {
741  // Runs on FILE thread.
742  DCHECK(file_thread_->message_loop() == MessageLoop::current());
743  bool result = false;
744
745  FilePath inspector_dir;
746  if (PathService::Get(chrome::DIR_INSPECTOR, &inspector_dir)) {
747    result = file_util::PathExists(inspector_dir);
748  }
749
750  have_inspector_files_ = result;
751}
752
753// Mac is currently not supported.
754#if (defined(OS_WIN) || defined(OS_LINUX)) && !defined(OS_CHROMEOS)
755
756bool BrowserProcessImpl::CanAutorestartForUpdate() const {
757  // Check if browser is in the background and if it needs to be restarted to
758  // apply a pending update.
759  return BrowserList::size() == 0 && BrowserList::WillKeepAlive() &&
760         Upgrade::IsUpdatePendingRestart();
761}
762
763// Switches to add when auto-restarting Chrome.
764const char* const kSwitchesToAddOnAutorestart[] = {
765  switches::kNoStartupWindow
766};
767
768void BrowserProcessImpl::RestartPersistentInstance() {
769  CommandLine* old_cl = CommandLine::ForCurrentProcess();
770  scoped_ptr<CommandLine> new_cl(new CommandLine(old_cl->GetProgram()));
771
772  std::map<std::string, CommandLine::StringType> switches =
773      old_cl->GetSwitches();
774
775  switches::RemoveSwitchesForAutostart(&switches);
776
777  // Append the rest of the switches (along with their values, if any)
778  // to the new command line
779  for (std::map<std::string, CommandLine::StringType>::const_iterator i =
780      switches.begin(); i != switches.end(); ++i) {
781      CommandLine::StringType switch_value = i->second;
782      if (switch_value.length() > 0) {
783        new_cl->AppendSwitchNative(i->first, i->second);
784      } else {
785        new_cl->AppendSwitch(i->first);
786      }
787  }
788
789  // Ensure that our desired switches are set on the new process.
790  for (size_t i = 0; i < arraysize(kSwitchesToAddOnAutorestart); ++i) {
791    if (!new_cl->HasSwitch(kSwitchesToAddOnAutorestart[i]))
792      new_cl->AppendSwitch(kSwitchesToAddOnAutorestart[i]);
793  }
794
795  DLOG(WARNING) << "Shutting down current instance of the browser.";
796  BrowserList::CloseAllBrowsersAndExit();
797
798  // Transfer ownership to Upgrade.
799  Upgrade::SetNewCommandLine(new_cl.release());
800}
801
802void BrowserProcessImpl::OnAutoupdateTimer() {
803  if (CanAutorestartForUpdate()) {
804    DLOG(WARNING) << "Detected update.  Restarting browser.";
805    RestartPersistentInstance();
806  }
807}
808
809#endif  // (defined(OS_WIN) || defined(OS_LINUX)) && !defined(OS_CHROMEOS)
810