Lazy initialization for ProcessesEventRouter.

Make it profile-scoped, not a singleton.
Construct EventRouter at ExtensionSystem creation time.
Implement EventRouter::Observer interface for lazy event router initialization, and use it for processes API.

BUG=156715,159265
[email protected]

Review URL: https://chromiumcodereview.appspot.com/11359081

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@166813 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/extensions/api/processes/processes_api.cc b/chrome/browser/extensions/api/processes/processes_api.cc
index 6c10f6e..e235a2a6 100644
--- a/chrome/browser/extensions/api/processes/processes_api.cc
+++ b/chrome/browser/extensions/api/processes/processes_api.cc
@@ -13,6 +13,7 @@
 #include "base/values.h"
 
 #include "chrome/browser/extensions/api/processes/processes_api_constants.h"
+#include "chrome/browser/extensions/api/processes/processes_api_factory.h"
 #include "chrome/browser/extensions/api/tabs/tabs_constants.h"
 #include "chrome/browser/extensions/event_router.h"
 #include "chrome/browser/extensions/extension_function_util.h"
@@ -212,12 +213,9 @@
 
 }  // namespace
 
-ProcessesEventRouter* ProcessesEventRouter::GetInstance() {
-  return Singleton<ProcessesEventRouter>::get();
-}
-
-ProcessesEventRouter::ProcessesEventRouter()
-    : listeners_(0),
+ProcessesEventRouter::ProcessesEventRouter(Profile* profile)
+    : profile_(profile),
+      listeners_(0),
       task_manager_listening_(false) {
 #if defined(ENABLE_TASK_MANAGER)
   model_ = TaskManager::GetInstance()->model();
@@ -244,10 +242,6 @@
 #endif  // defined(ENABLE_TASK_MANAGER)
 }
 
-void ProcessesEventRouter::ObserveProfile(Profile* profile) {
-  profiles_.insert(profile);
-}
-
 void ProcessesEventRouter::ListenerAdded() {
 #if defined(ENABLE_TASK_MANAGER)
   // The task manager has its own ref count to balance other callers of
@@ -323,7 +317,7 @@
 
   args->Append(process);
 
-  NotifyProfiles(keys::kOnCreated, args.Pass());
+  DispatchEvent(keys::kOnCreated, args.Pass());
 #endif  // defined(ENABLE_TASK_MANAGER)
 }
 
@@ -370,7 +364,7 @@
 
     scoped_ptr<ListValue> args(new ListValue());
     args->Append(processes);
-    NotifyProfiles(keys::kOnUpdated, args.Pass());
+    DispatchEvent(keys::kOnUpdated, args.Pass());
   }
 
   if (updated_memory) {
@@ -389,7 +383,7 @@
 
     scoped_ptr<ListValue> args(new ListValue());
     args->Append(processes);
-    NotifyProfiles(keys::kOnUpdatedWithMemory, args.Pass());
+    DispatchEvent(keys::kOnUpdatedWithMemory, args.Pass());
   }
 #endif  // defined(ENABLE_TASK_MANAGER)
 }
@@ -418,7 +412,7 @@
   // Third arg: The exit code for the process.
   args->Append(Value::CreateIntegerValue(0));
 
-  NotifyProfiles(keys::kOnExited, args.Pass());
+  DispatchEvent(keys::kOnExited, args.Pass());
 #endif  // defined(ENABLE_TASK_MANAGER)
 }
 
@@ -448,7 +442,7 @@
   scoped_ptr<ListValue> args(new ListValue());
   args->Append(process);
 
-  NotifyProfiles(keys::kOnUnresponsive, args.Pass());
+  DispatchEvent(keys::kOnUnresponsive, args.Pass());
 #endif  // defined(ENABLE_TASK_MANAGER)
 }
 
@@ -468,47 +462,56 @@
   // Third arg: The exit code for the process.
   args->Append(Value::CreateIntegerValue(details->exit_code));
 
-  NotifyProfiles(keys::kOnExited, args.Pass());
+  DispatchEvent(keys::kOnExited, args.Pass());
 #endif  // defined(ENABLE_TASK_MANAGER)
 }
 
-void ProcessesEventRouter::DispatchEvent(Profile* profile,
-                                         const char* event_name,
+void ProcessesEventRouter::DispatchEvent(const char* event_name,
                                          scoped_ptr<ListValue> event_args) {
-  if (profile && extensions::ExtensionSystem::Get(profile)->event_router()) {
-    extensions::ExtensionSystem::Get(profile)->event_router()->
+  if (extensions::ExtensionSystem::Get(profile_)->event_router()) {
+    extensions::ExtensionSystem::Get(profile_)->event_router()->
         DispatchEventToRenderers(event_name, event_args.Pass(), NULL, GURL(),
                                  extensions::EventFilteringInfo());
   }
 }
 
-void ProcessesEventRouter::NotifyProfiles(const char* event_name,
-                                          scoped_ptr<ListValue> event_args) {
-  for (ProfileSet::iterator it = profiles_.begin();
-       it != profiles_.end(); ++it) {
-    Profile* profile = *it;
-    scoped_ptr<ListValue> event_args_copy(event_args->DeepCopy());
-    DispatchEvent(profile, event_name, event_args_copy.Pass());
-  }
+bool ProcessesEventRouter::HasEventListeners(const std::string& event_name) {
+  extensions::EventRouter* router =
+      extensions::ExtensionSystem::Get(profile_)->event_router();
+    if (router && router->HasEventListener(event_name))
+      return true;
+  return false;
 }
 
-// In order to determine whether there are any listeners for the event of
-// interest, we need to ask each profile whether it has one registered.
-// We only need to look for the profiles that have registered with the
-// this extension API.
-bool ProcessesEventRouter::HasEventListeners(const std::string& event_name) {
-  for (ProfileSet::iterator it = profiles_.begin();
-       it != profiles_.end(); ++it) {
-    Profile* profile = *it;
-    extensions::EventRouter* router =
-        extensions::ExtensionSystem::Get(profile)->event_router();
-    if (!router)
-      continue;
+ProcessesAPI::ProcessesAPI(Profile* profile)
+    : profile_(profile),
+      processes_event_router_(new ProcessesEventRouter(profile)) {
+  ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
+      this, processes_api_constants::kOnUpdated);
+  ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
+      this, processes_api_constants::kOnUpdatedWithMemory);
+}
 
-    if (router->HasEventListener(event_name))
-      return true;
-  }
-  return false;
+ProcessesAPI::~ProcessesAPI() {
+  ExtensionSystem::Get(profile_)->event_router()->UnregisterObserver(this);
+}
+
+// static
+ProcessesAPI* ProcessesAPI::Get(Profile* profile) {
+  return ProcessesAPIFactory::GetForProfile(profile);
+}
+
+void ProcessesAPI::OnListenerAdded(const std::string& event_name) {
+  // We lazily tell the TaskManager to start updating when listeners to the
+  // processes.onUpdated or processes.onUpdatedWithMemory events arrive.
+  processes_event_router_->ListenerAdded();
+}
+
+void ProcessesAPI::OnListenerRemoved(const std::string& event_name) {
+  // If a processes.onUpdated or processes.onUpdatedWithMemory event listener
+  // is removed (or a process with one exits), then we let the extension API
+  // know that it has one fewer listener.
+  processes_event_router_->ListenerRemoved();
 }
 
 GetProcessIdForTabFunction::GetProcessIdForTabFunction() : tab_id_(-1) {
@@ -526,14 +529,16 @@
   // which will invoke the callback once we have returned from this function.
   // Otherwise, wait for the notification that the task manager is done with
   // the data gathering.
-  if (ProcessesEventRouter::GetInstance()->is_task_manager_listening()) {
+  if (ProcessesAPI::Get(profile_)->processes_event_router()->
+      is_task_manager_listening()) {
     MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
         &GetProcessIdForTabFunction::GetProcessIdForTab, this));
   } else {
     registrar_.Add(this,
                    chrome::NOTIFICATION_TASK_MANAGER_CHILD_PROCESSES_DATA_READY,
                    content::NotificationService::AllSources());
-    ProcessesEventRouter::GetInstance()->StartTaskManagerListening();
+    ProcessesAPI::Get(profile_)->processes_event_router()->
+        StartTaskManagerListening();
   }
 
   return true;
@@ -587,14 +592,16 @@
   // which will invoke the callback once we have returned from this function.
   // Otherwise, wait for the notification that the task manager is done with
   // the data gathering.
-  if (ProcessesEventRouter::GetInstance()->is_task_manager_listening()) {
+  if (ProcessesAPI::Get(profile_)->processes_event_router()->
+      is_task_manager_listening()) {
     MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
         &TerminateFunction::TerminateProcess, this));
   } else {
     registrar_.Add(this,
                    chrome::NOTIFICATION_TASK_MANAGER_CHILD_PROCESSES_DATA_READY,
                    content::NotificationService::AllSources());
-    ProcessesEventRouter::GetInstance()->StartTaskManagerListening();
+    ProcessesAPI::Get(profile_)->processes_event_router()->
+        StartTaskManagerListening();
   }
 
   return true;
@@ -673,14 +680,16 @@
   // which will invoke the callback once we have returned from this function.
   // Otherwise, wait for the notification that the task manager is done with
   // the data gathering.
-  if (ProcessesEventRouter::GetInstance()->is_task_manager_listening()) {
+  if (ProcessesAPI::Get(profile_)->processes_event_router()->
+      is_task_manager_listening()) {
     MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
         &GetProcessInfoFunction::GatherProcessInfo, this));
   } else {
     registrar_.Add(this,
                    chrome::NOTIFICATION_TASK_MANAGER_CHILD_PROCESSES_DATA_READY,
                    content::NotificationService::AllSources());
-    ProcessesEventRouter::GetInstance()->StartTaskManagerListening();
+    ProcessesAPI::Get(profile_)->processes_event_router()->
+        StartTaskManagerListening();
   }
   return true;
 
diff --git a/chrome/browser/extensions/api/processes/processes_api.h b/chrome/browser/extensions/api/processes/processes_api.h
index c30169a..d4a6bade 100644
--- a/chrome/browser/extensions/api/processes/processes_api.h
+++ b/chrome/browser/extensions/api/processes/processes_api.h
@@ -8,12 +8,17 @@
 #include <set>
 #include <string>
 
+#include "base/memory/scoped_ptr.h"
+#include "chrome/browser/extensions/event_router.h"
 #include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/profiles/profile_keyed_service.h"
 #include "chrome/browser/task_manager/task_manager.h"
 #include "content/public/browser/notification_registrar.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_widget_host.h"
 
+class Profile;
+
 namespace base {
 class ListValue;
 }
@@ -25,11 +30,8 @@
 class ProcessesEventRouter : public TaskManagerModelObserver,
                              public content::NotificationObserver {
  public:
-  // Single instance of the event router.
-  static ProcessesEventRouter* GetInstance();
-
-  // Safe to call multiple times.
-  void ObserveProfile(Profile* profile);
+  explicit ProcessesEventRouter(Profile* profile);
+  virtual ~ProcessesEventRouter();
 
   // Called when an extension process wants to listen to process events.
   void ListenerAdded();
@@ -46,11 +48,6 @@
   int num_listeners() { return listeners_; }
 
  private:
-  friend struct DefaultSingletonTraits<ProcessesEventRouter>;
-
-  ProcessesEventRouter();
-  virtual ~ProcessesEventRouter();
-
   // content::NotificationObserver implementation.
   virtual void Observe(int type,
                        const content::NotificationSource& source,
@@ -69,11 +66,7 @@
       content::RenderProcessHost* rph,
       content::RenderProcessHost::RendererClosedDetails* details);
 
-  void NotifyProfiles(const char* event_name,
-                      scoped_ptr<base::ListValue> event_args);
-
-  void DispatchEvent(Profile* profile,
-                     const char* event_name,
+  void DispatchEvent(const char* event_name,
                      scoped_ptr<base::ListValue> event_args);
 
   // Determines whether there is a registered listener for the specified event.
@@ -83,9 +76,7 @@
   // Used for tracking registrations to process related notifications.
   content::NotificationRegistrar registrar_;
 
-  // Registered profiles.
-  typedef std::set<Profile*> ProfileSet;
-  ProfileSet profiles_;
+  Profile* profile_;
 
   // TaskManager to observe for updates.
   TaskManagerModel* model_;
@@ -100,6 +91,32 @@
   DISALLOW_COPY_AND_ASSIGN(ProcessesEventRouter);
 };
 
+// The profile-keyed service that manages the processes extension API.
+class ProcessesAPI : public ProfileKeyedService,
+                     public EventRouter::Observer {
+ public:
+  explicit ProcessesAPI(Profile* profile);
+  virtual ~ProcessesAPI();
+
+  // Convenience method to get the ProcessesAPI for a profile.
+  static ProcessesAPI* Get(Profile* profile);
+
+  ProcessesEventRouter* processes_event_router() {
+    return processes_event_router_.get();
+  }
+
+  // EventRouter::Observer implementation.
+  virtual void OnListenerAdded(const std::string& event_name) OVERRIDE;
+  virtual void OnListenerRemoved(const std::string& event_name) OVERRIDE;
+
+ private:
+  Profile* profile_;
+
+  // TODO(yoz): Currently, the event router cannot be started lazily
+  // because some API functions use it. It ought to be possible to fix
+  // by moving some state to ProcessesAPI from the event router.
+  scoped_ptr<extensions::ProcessesEventRouter> processes_event_router_;
+};
 
 // This extension function returns the Process object for the renderer process
 // currently in use by the specified Tab.
diff --git a/chrome/browser/extensions/api/processes/processes_api_factory.cc b/chrome/browser/extensions/api/processes/processes_api_factory.cc
new file mode 100644
index 0000000..8a8ad9c
--- /dev/null
+++ b/chrome/browser/extensions/api/processes/processes_api_factory.cc
@@ -0,0 +1,51 @@
+// 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/extensions/api/processes/processes_api_factory.h"
+
+#include "chrome/browser/extensions/api/processes/processes_api.h"
+#include "chrome/browser/extensions/extension_system_factory.h"
+#include "chrome/browser/profiles/profile_dependency_manager.h"
+
+namespace extensions {
+
+// static
+ProcessesAPI* ProcessesAPIFactory::GetForProfile(
+    Profile* profile) {
+  return static_cast<ProcessesAPI*>(
+      GetInstance()->GetServiceForProfile(profile, true));
+}
+
+// static
+ProcessesAPIFactory* ProcessesAPIFactory::GetInstance() {
+  return Singleton<ProcessesAPIFactory>::get();
+}
+
+ProcessesAPIFactory::ProcessesAPIFactory()
+    : ProfileKeyedServiceFactory("ProcessesAPI",
+                                 ProfileDependencyManager::GetInstance()) {
+  DependsOn(ExtensionSystemFactory::GetInstance());
+}
+
+ProcessesAPIFactory::~ProcessesAPIFactory() {
+}
+
+ProfileKeyedService* ProcessesAPIFactory::BuildServiceInstanceFor(
+    Profile* profile) const {
+  return new ProcessesAPI(profile);
+}
+
+bool ProcessesAPIFactory::ServiceRedirectedInIncognito() const {
+  return true;
+}
+
+bool ProcessesAPIFactory::ServiceIsCreatedWithProfile() const {
+  return true;
+}
+
+bool ProcessesAPIFactory::ServiceIsNULLWhileTesting() const {
+  return true;
+}
+
+}  // namespace extensions
diff --git a/chrome/browser/extensions/api/processes/processes_api_factory.h b/chrome/browser/extensions/api/processes/processes_api_factory.h
new file mode 100644
index 0000000..90f2f4d
--- /dev/null
+++ b/chrome/browser/extensions/api/processes/processes_api_factory.h
@@ -0,0 +1,36 @@
+// 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.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_API_PROCESSES_PROCESSES_API_FACTORY_H__
+#define CHROME_BROWSER_EXTENSIONS_API_PROCESSES_PROCESSES_API_FACTORY_H__
+
+#include "base/memory/singleton.h"
+#include "chrome/browser/profiles/profile_keyed_service_factory.h"
+
+namespace extensions {
+class ProcessesAPI;
+
+class ProcessesAPIFactory : public ProfileKeyedServiceFactory {
+ public:
+  static ProcessesAPI* GetForProfile(Profile* profile);
+
+  static ProcessesAPIFactory* GetInstance();
+
+ private:
+  friend struct DefaultSingletonTraits<ProcessesAPIFactory>;
+
+  ProcessesAPIFactory();
+  virtual ~ProcessesAPIFactory();
+
+  // ProfileKeyedBaseFactory implementation.
+  virtual ProfileKeyedService* BuildServiceInstanceFor(
+      Profile* profile) const OVERRIDE;
+  virtual bool ServiceRedirectedInIncognito() const OVERRIDE;
+  virtual bool ServiceIsCreatedWithProfile() const OVERRIDE;
+  virtual bool ServiceIsNULLWhileTesting() const OVERRIDE;
+};
+
+}  // namespace extensions
+
+#endif  // CHROME_BROWSER_EXTENSIONS_API_PROCESSES_PROCESSES_API_FACTORY_H__
diff --git a/chrome/browser/extensions/event_router.cc b/chrome/browser/extensions/event_router.cc
index b6683a6..19358599 100644
--- a/chrome/browser/extensions/event_router.cc
+++ b/chrome/browser/extensions/event_router.cc
@@ -13,8 +13,6 @@
 #include "base/values.h"
 #include "base/version.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/extensions/api/processes/processes_api_constants.h"
-#include "chrome/browser/extensions/api/processes/processes_api.h"
 #include "chrome/browser/extensions/api/runtime/runtime_api.h"
 #include "chrome/browser/extensions/api/web_request/web_request_api.h"
 #include "chrome/browser/extensions/event_names.h"
@@ -122,8 +120,6 @@
 
 EventRouter::EventRouter(Profile* profile, ExtensionPrefs* extension_prefs)
     : profile_(profile),
-      extension_devtools_manager_(
-          ExtensionSystem::Get(profile)->devtools_manager()),
       listeners_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
       dispatch_chrome_updated_event_(false) {
   registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
@@ -166,23 +162,39 @@
   listeners_.RemoveListener(&listener);
 }
 
+void EventRouter::RegisterObserver(Observer* observer,
+                                   const std::string& event_name) {
+  observers_[event_name] = observer;
+}
+
+void EventRouter::UnregisterObserver(Observer* observer) {
+  std::vector<ObserverMap::iterator> iters_to_remove;
+  for (ObserverMap::iterator iter = observers_.begin();
+       iter != observers_.end(); ++iter) {
+    if (iter->second == observer)
+      iters_to_remove.push_back(iter);
+  }
+  for (size_t i = 0; i < iters_to_remove.size(); ++i)
+    observers_.erase(iters_to_remove[i]);
+}
+
 void EventRouter::OnListenerAdded(const EventListener* listener) {
   // We don't care about lazy events being added.
   if (!listener->process)
     return;
 
-  if (extension_devtools_manager_.get())
-    extension_devtools_manager_->AddEventListener(listener->event_name,
-                                                  listener->process->GetID());
-
-  // We lazily tell the TaskManager to start updating when listeners to the
-  // processes.onUpdated or processes.onUpdatedWithMemory events arrive.
   const std::string& event_name = listener->event_name;
-  if (event_name.compare(
-          extensions::processes_api_constants::kOnUpdated) == 0 ||
-      event_name.compare(
-          extensions::processes_api_constants::kOnUpdatedWithMemory) == 0)
-    extensions::ProcessesEventRouter::GetInstance()->ListenerAdded();
+  ObserverMap::iterator observer = observers_.find(event_name);
+  if (observer != observers_.end())
+    observer->second->OnListenerAdded(event_name);
+
+  // TODO(yoz): Migrate these to become EventRouter observers.
+  // EventRouter shouldn't need to know about them.
+  ExtensionDevToolsManager* extension_devtools_manager =
+      ExtensionSystem::Get(profile_)->devtools_manager();
+  if (extension_devtools_manager)
+    extension_devtools_manager->AddEventListener(event_name,
+                                                 listener->process->GetID());
 
   if (SystemInfoEventRouter::IsSystemInfoEvent(event_name))
     SystemInfoEventRouter::GetInstance()->AddEventListener(event_name);
@@ -194,23 +206,22 @@
     return;
 
   const std::string& event_name = listener->event_name;
-  if (extension_devtools_manager_.get())
-    extension_devtools_manager_->RemoveEventListener(
-        event_name, listener->process->GetID());
+  ObserverMap::iterator observer = observers_.find(event_name);
+  if (observer != observers_.end())
+    observer->second->OnListenerRemoved(event_name);
 
-  // If a processes.onUpdated or processes.onUpdatedWithMemory event listener
-  // is removed (or a process with one exits), then we let the extension API
-  // know that it has one fewer listener.
-  if (event_name.compare(
-          extensions::processes_api_constants::kOnUpdated) == 0 ||
-      event_name.compare(
-          extensions::processes_api_constants::kOnUpdatedWithMemory) == 0)
-    extensions::ProcessesEventRouter::GetInstance()->ListenerRemoved();
+  // TODO(yoz): Migrate these to become EventRouter observers.
+  // EventRouter shouldn't need to know about them.
+  ExtensionDevToolsManager* extension_devtools_manager =
+      ExtensionSystem::Get(profile_)->devtools_manager();
+  if (extension_devtools_manager)
+    extension_devtools_manager->RemoveEventListener(
+        event_name, listener->process->GetID());
 
   BrowserThread::PostTask(
       BrowserThread::IO, FROM_HERE,
       base::Bind(&NotifyEventListenerRemovedOnIOThread,
-                 profile_, listener->extension_id, listener->event_name));
+                 profile_, listener->extension_id, event_name));
 
   if (SystemInfoEventRouter::IsSystemInfoEvent(event_name))
     SystemInfoEventRouter::GetInstance()->RemoveEventListener(event_name);
diff --git a/chrome/browser/extensions/event_router.h b/chrome/browser/extensions/event_router.h
index cbfb1b8..94f81da 100644
--- a/chrome/browser/extensions/event_router.h
+++ b/chrome/browser/extensions/event_router.h
@@ -22,7 +22,6 @@
 #include "ipc/ipc_sender.h"
 
 class GURL;
-class ExtensionDevToolsManager;
 class Profile;
 
 namespace content {
@@ -47,6 +46,16 @@
     USER_GESTURE_NOT_ENABLED = 2,
   };
 
+  // Observers register interest in events with a particular name and are
+  // notified when a listener is added or removed for that |event_name|.
+  class Observer {
+   public:
+    // Called when a listener is added.
+    virtual void OnListenerAdded(const std::string& event_name) {}
+    // Called when a listener is removed.
+    virtual void OnListenerRemoved(const std::string& event_name) {}
+  };
+
   // Sends an event via ipc_sender to the given extension. Can be called on any
   // thread.
   static void DispatchEvent(IPC::Sender* ipc_sender,
@@ -73,6 +82,15 @@
 
   EventListenerMap& listeners() { return listeners_; }
 
+  // Registers an observer to be notified when an event listener for
+  // |event_name| is added or removed. There can currently be only one observer
+  // for each distinct |event_name|.
+  void RegisterObserver(Observer* observer,
+                        const std::string& event_name);
+
+  // Unregisters an observer from all events.
+  void UnregisterObserver(Observer* observer);
+
   // Add or remove the extension as having a lazy background page that listens
   // to the event. The difference from the above methods is that these will be
   // remembered even after the process goes away. We use this list to decide
@@ -249,10 +267,11 @@
 
   content::NotificationRegistrar registrar_;
 
-  scoped_refptr<ExtensionDevToolsManager> extension_devtools_manager_;
-
   EventListenerMap listeners_;
 
+  typedef std::map<std::string, Observer*> ObserverMap;
+  ObserverMap observers_;
+
   // True if we should dispatch the event signalling that Chrome was updated
   // upon loading an extension.
   bool dispatch_chrome_updated_event_;
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc
index e2381e7..8bb1afb 100644
--- a/chrome/browser/extensions/extension_service.cc
+++ b/chrome/browser/extensions/extension_service.cc
@@ -39,7 +39,6 @@
 #include "chrome/browser/extensions/api/management/management_api.h"
 #include "chrome/browser/extensions/api/media_galleries_private/media_galleries_private_event_router.h"
 #include "chrome/browser/extensions/api/preference/preference_api.h"
-#include "chrome/browser/extensions/api/processes/processes_api.h"
 #include "chrome/browser/extensions/api/runtime/runtime_api.h"
 #include "chrome/browser/extensions/api/push_messaging/push_messaging_api.h"
 #include "chrome/browser/extensions/api/web_navigation/web_navigation_api.h"
@@ -528,7 +527,6 @@
   cookies_event_router_.reset(
       new extensions::ExtensionCookiesEventRouter(profile_));
   management_event_router_.reset(new ExtensionManagementEventRouter(profile_));
-  extensions::ProcessesEventRouter::GetInstance()->ObserveProfile(profile_);
   web_navigation_event_router_.reset(
       new extensions::WebNavigationEventRouter(profile_));
   font_settings_event_router_.reset(
diff --git a/chrome/browser/extensions/extension_service.h b/chrome/browser/extensions/extension_service.h
index 2cac535..0a2abc3 100644
--- a/chrome/browser/extensions/extension_service.h
+++ b/chrome/browser/extensions/extension_service.h
@@ -897,6 +897,8 @@
   // Flag to make sure event routers are only initialized once.
   bool event_routers_initialized_;
 
+  // TODO(yoz): None of these should be owned by ExtensionService.
+  // crbug.com/159265
   scoped_ptr<HistoryExtensionEventRouter> history_event_router_;
 
   scoped_ptr<extensions::BrowserEventRouter> browser_event_router_;
diff --git a/chrome/browser/extensions/extension_system.cc b/chrome/browser/extensions/extension_system.cc
index cf5b5d4..8e54896 100644
--- a/chrome/browser/extensions/extension_system.cc
+++ b/chrome/browser/extensions/extension_system.cc
@@ -85,6 +85,8 @@
       profile_->GetPath().AppendASCII(ExtensionService::kInstallDirectoryName),
       ExtensionPrefValueMapFactory::GetForProfile(profile_)));
   extension_prefs_->Init(extensions_disabled);
+  lazy_background_task_queue_.reset(new LazyBackgroundTaskQueue(profile_));
+  event_router_.reset(new EventRouter(profile_, extension_prefs_.get()));
 
   state_store_.reset(new StateStore(
       profile_,
@@ -102,10 +104,7 @@
 void ExtensionSystemImpl::Shared::Init(bool extensions_enabled) {
   const CommandLine* command_line = CommandLine::ForCurrentProcess();
 
-  lazy_background_task_queue_.reset(new LazyBackgroundTaskQueue(profile_));
   message_service_.reset(new MessageService(lazy_background_task_queue_.get()));
-  extension_event_router_.reset(new EventRouter(profile_,
-                                                extension_prefs_.get()));
   navigation_observer_.reset(new NavigationObserver(profile_));
 
   ExtensionErrorReporter::Init(true);  // allow noisy errors.
@@ -237,7 +236,7 @@
 }
 
 EventRouter* ExtensionSystemImpl::Shared::event_router() {
-  return extension_event_router_.get();
+  return event_router_.get();
 }
 
 //
diff --git a/chrome/browser/extensions/extension_system.h b/chrome/browser/extensions/extension_system.h
index 51180515..4937a55 100644
--- a/chrome/browser/extensions/extension_system.h
+++ b/chrome/browser/extensions/extension_system.h
@@ -216,8 +216,8 @@
     // LazyBackgroundTaskQueue is a dependency of
     // MessageService and EventRouter.
     scoped_ptr<LazyBackgroundTaskQueue> lazy_background_task_queue_;
+    scoped_ptr<EventRouter> event_router_;
     scoped_ptr<MessageService> message_service_;
-    scoped_ptr<EventRouter> extension_event_router_;
     scoped_ptr<NavigationObserver> navigation_observer_;
     scoped_refptr<UserScriptMaster> user_script_master_;
     // ExtensionService depends on ExtensionPrefs and StateStore.
diff --git a/chrome/browser/profiles/profile_dependency_manager.cc b/chrome/browser/profiles/profile_dependency_manager.cc
index 7c969be..44a971e 100644
--- a/chrome/browser/profiles/profile_dependency_manager.cc
+++ b/chrome/browser/profiles/profile_dependency_manager.cc
@@ -16,8 +16,9 @@
 #include "chrome/browser/download/download_service_factory.h"
 #include "chrome/browser/extensions/api/commands/command_service_factory.h"
 #include "chrome/browser/extensions/api/discovery/suggested_links_registry_factory.h"
-#include "chrome/browser/extensions/app_restore_service_factory.h"
+#include "chrome/browser/extensions/api/processes/processes_api_factory.h"
 #include "chrome/browser/extensions/api/tab_capture/tab_capture_registry_factory.h"
+#include "chrome/browser/extensions/app_restore_service_factory.h"
 #include "chrome/browser/extensions/extension_system_factory.h"
 #include "chrome/browser/favicon/favicon_service_factory.h"
 #include "chrome/browser/google/google_url_tracker_factory.h"
@@ -223,6 +224,7 @@
   extensions::CommandServiceFactory::GetInstance();
   extensions::SuggestedLinksRegistryFactory::GetInstance();
   extensions::ExtensionSystemFactory::GetInstance();
+  extensions::ProcessesAPIFactory::GetInstance();
   extensions::TabCaptureRegistryFactory::GetInstance();
 #endif
   FaviconServiceFactory::GetInstance();
diff --git a/chrome/chrome_browser_extensions.gypi b/chrome/chrome_browser_extensions.gypi
index 2cfbca82..ef88607 100644
--- a/chrome/chrome_browser_extensions.gypi
+++ b/chrome/chrome_browser_extensions.gypi
@@ -237,6 +237,8 @@
         'browser/extensions/api/processes/processes_api.h',
         'browser/extensions/api/processes/processes_api_constants.cc',
         'browser/extensions/api/processes/processes_api_constants.h',
+        'browser/extensions/api/processes/processes_api_factory.cc',
+        'browser/extensions/api/processes/processes_api_factory.h',
         'browser/extensions/api/proxy/proxy_api.cc',
         'browser/extensions/api/proxy/proxy_api.h',
         'browser/extensions/api/proxy/proxy_api_constants.cc',