summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorphajdan.jr@chromium.org <phajdan.jr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-06 08:19:49 +0000
committerphajdan.jr@chromium.org <phajdan.jr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-06 08:19:49 +0000
commit8a17bd55d6f0336a3d8e3c66af61a0a3b074dfe9 (patch)
treec46ba5bfb499017b07cacdb6f8665070e77bbb3a /chrome
parent31e8a0105e34d04ec14a5387b907b90a776d82f5 (diff)
downloadchromium_src-8a17bd55d6f0336a3d8e3c66af61a0a3b074dfe9.zip
chromium_src-8a17bd55d6f0336a3d8e3c66af61a0a3b074dfe9.tar.gz
chromium_src-8a17bd55d6f0336a3d8e3c66af61a0a3b074dfe9.tar.bz2
Display extension processes in task manager.
This is the first part of the change. I will submit code to listen for new extension processes while task manager is open in following patch(es). TEST=Install an extension which renders to the extension shelf, like Buildbot Monitor from http://dev.chromium.org/developers/design-documents/extensions/samples. Open the task manager. You should see the extension process. http://crbug.com/12127 Review URL: http://codereview.chromium.org/115858 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@17826 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/app/generated_resources.grd3
-rw-r--r--chrome/browser/extensions/extension_host.cc11
-rw-r--r--chrome/browser/extensions/extension_host.h11
-rw-r--r--chrome/browser/extensions/extension_process_manager.cc28
-rw-r--r--chrome/browser/extensions/extension_process_manager.h22
-rw-r--r--chrome/browser/extensions/extension_view_unittest.cc2
-rw-r--r--chrome/browser/tab_contents/tab_contents.h5
-rw-r--r--chrome/browser/task_manager.cc4
-rw-r--r--chrome/browser/task_manager_resource_providers.cc126
-rw-r--r--chrome/browser/task_manager_resource_providers.h70
10 files changed, 261 insertions, 21 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index b374261..bcdabc2 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -1863,6 +1863,9 @@ each locale. -->
<message name="IDS_TASK_MANAGER_WEB_BROWSER_CELL_TEXT" desc="The text of the web browser process row">
Browser
</message>
+ <message name="IDS_TASK_MANAGER_EXTENSION_PREFIX" desc="The prefix for a Task Manager extension row (always visible if the extension has a view)">
+ Extension: <ph name="EXTENSION_NAME">$1<ex>Sample Extension</ex></ph>
+ </message>
<message name="IDS_TASK_MANAGER_TAB_PREFIX" desc="The prefix for a Task Manager Tab row">
Tab: <ph name="TAB_NAME">$1<ex>Google</ex></ph>
</message>
diff --git a/chrome/browser/extensions/extension_host.cc b/chrome/browser/extensions/extension_host.cc
index 9509577..c9eeda8 100644
--- a/chrome/browser/extensions/extension_host.cc
+++ b/chrome/browser/extensions/extension_host.cc
@@ -10,6 +10,7 @@
#include "chrome/browser/browser_process.h"
#include "chrome/browser/debugger/devtools_manager.h"
#include "chrome/browser/extensions/extension_message_service.h"
+#include "chrome/browser/extensions/extension_process_manager.h"
#include "chrome/browser/extensions/extension_view.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
@@ -28,8 +29,10 @@
#include "webkit/glue/context_menu.h"
-ExtensionHost::ExtensionHost(Extension* extension, SiteInstance* site_instance)
+ExtensionHost::ExtensionHost(Extension* extension, SiteInstance* site_instance,
+ ExtensionProcessManager* manager)
: extension_(extension),
+ manager_(manager),
#if defined(OS_WIN)
view_(NULL),
#endif
@@ -40,9 +43,15 @@ ExtensionHost::ExtensionHost(Extension* extension, SiteInstance* site_instance)
}
ExtensionHost::~ExtensionHost() {
+ if (manager_) // To allow passing NULL in tests.
+ manager_->OnExtensionHostDestroyed(this);
render_view_host_->Shutdown(); // deletes render_view_host
}
+RenderProcessHost* ExtensionHost::render_process_host() const {
+ return render_view_host_->process();
+}
+
SiteInstance* ExtensionHost::site_instance() const {
return render_view_host_->site_instance();
}
diff --git a/chrome/browser/extensions/extension_host.h b/chrome/browser/extensions/extension_host.h
index ba7c283..751e07f 100644
--- a/chrome/browser/extensions/extension_host.h
+++ b/chrome/browser/extensions/extension_host.h
@@ -5,12 +5,16 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_HOST_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_HOST_H_
+#include <string>
+
#include "chrome/browser/renderer_host/render_view_host_delegate.h"
#include "chrome/browser/tab_contents/render_view_host_delegate_helper.h"
class Browser;
class Extension;
+class ExtensionProcessManager;
class ExtensionView;
+class RenderProcessHost;
class RenderWidgetHost;
class RenderWidgetHostView;
class TabContents;
@@ -24,7 +28,8 @@ class ExtensionHost : public RenderViewHostDelegate,
public RenderViewHostDelegate::View,
public ExtensionFunctionDispatcher::Delegate {
public:
- ExtensionHost(Extension* extension, SiteInstance* site_instance);
+ ExtensionHost(Extension* extension, SiteInstance* site_instance,
+ ExtensionProcessManager* manager);
~ExtensionHost();
#if defined(TOOLKIT_VIEWS)
@@ -33,6 +38,7 @@ class ExtensionHost : public RenderViewHostDelegate,
#endif
Extension* extension() { return extension_; }
RenderViewHost* render_view_host() const { return render_view_host_; }
+ RenderProcessHost* render_process_host() const;
SiteInstance* site_instance() const;
bool did_stop_loading() const { return did_stop_loading_; }
@@ -86,6 +92,9 @@ class ExtensionHost : public RenderViewHostDelegate,
// The extension that we're hosting in this view.
Extension* extension_;
+ // Manager which created us (to notify upon destruction).
+ ExtensionProcessManager* manager_;
+
#if defined(TOOLKIT_VIEWS)
// Optional view that shows the rendered content in the UI.
ExtensionView* view_;
diff --git a/chrome/browser/extensions/extension_process_manager.cc b/chrome/browser/extensions/extension_process_manager.cc
index f2bcad4..3aab7fb 100644
--- a/chrome/browser/extensions/extension_process_manager.cc
+++ b/chrome/browser/extensions/extension_process_manager.cc
@@ -37,8 +37,11 @@ ExtensionProcessManager::ExtensionProcessManager(Profile* profile)
}
ExtensionProcessManager::~ExtensionProcessManager() {
- for (ExtensionHostList::iterator iter = background_hosts_.begin();
- iter != background_hosts_.end(); ++iter)
+ // Copy background_hosts_ to avoid iterator invalidation issues.
+ ExtensionHostSet to_delete(background_hosts_.begin(),
+ background_hosts_.end());
+ ExtensionHostSet::iterator iter;
+ for (iter = to_delete.begin(); iter != to_delete.end(); ++iter)
delete *iter;
}
@@ -46,17 +49,20 @@ ExtensionProcessManager::~ExtensionProcessManager() {
ExtensionView* ExtensionProcessManager::CreateView(Extension* extension,
const GURL& url,
Browser* browser) {
- return new ExtensionView(
- new ExtensionHost(extension, GetSiteInstanceForURL(url)), browser, url);
+ ExtensionHost* host = new ExtensionHost(extension,
+ GetSiteInstanceForURL(url), this);
+ all_hosts_.insert(host);
+ return new ExtensionView(host, browser, url);
}
#endif
void ExtensionProcessManager::CreateBackgroundHost(Extension* extension,
const GURL& url) {
ExtensionHost* host =
- new ExtensionHost(extension, GetSiteInstanceForURL(url));
+ new ExtensionHost(extension, GetSiteInstanceForURL(url), this);
host->CreateRenderView(url, NULL); // create a RenderViewHost with no view
- background_hosts_.push_back(host);
+ all_hosts_.insert(host);
+ background_hosts_.insert(host);
}
SiteInstance* ExtensionProcessManager::GetSiteInstanceForURL(const GURL& url) {
@@ -75,12 +81,13 @@ void ExtensionProcessManager::Observe(NotificationType type,
case NotificationType::EXTENSION_UNLOADED: {
Extension* extension = Details<Extension>(details).ptr();
- for (ExtensionHostList::iterator iter = background_hosts_.begin();
+ for (ExtensionHostSet::iterator iter = background_hosts_.begin();
iter != background_hosts_.end(); ++iter) {
ExtensionHost* host = *iter;
if (host->extension()->id() == extension->id()) {
- background_hosts_.erase(iter);
delete host;
+ // |host| should deregister itself from our structures.
+ DCHECK(background_hosts_.find(host) == background_hosts_.end());
break;
}
}
@@ -91,3 +98,8 @@ void ExtensionProcessManager::Observe(NotificationType type,
NOTREACHED();
}
}
+
+void ExtensionProcessManager::OnExtensionHostDestroyed(ExtensionHost* host) {
+ all_hosts_.erase(host);
+ background_hosts_.erase(host);
+}
diff --git a/chrome/browser/extensions/extension_process_manager.h b/chrome/browser/extensions/extension_process_manager.h
index 1b99933..48ce382 100644
--- a/chrome/browser/extensions/extension_process_manager.h
+++ b/chrome/browser/extensions/extension_process_manager.h
@@ -5,7 +5,7 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_PROCESS_MANAGER_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_PROCESS_MANAGER_H_
-#include <list>
+#include <set>
#include "base/ref_counted.h"
#include "chrome/common/notification_registrar.h"
@@ -25,7 +25,7 @@ class SiteInstance;
// of this class per Profile (including OTR).
class ExtensionProcessManager : public NotificationObserver {
public:
- ExtensionProcessManager(Profile* profile);
+ explicit ExtensionProcessManager(Profile* profile);
~ExtensionProcessManager();
#if defined(TOOLKIT_VIEWS)
@@ -48,13 +48,23 @@ class ExtensionProcessManager : public NotificationObserver {
const NotificationSource& source,
const NotificationDetails& details);
- private:
- typedef std::list<ExtensionHost*> ExtensionHostList;
+ typedef std::set<ExtensionHost*> ExtensionHostSet;
+ typedef ExtensionHostSet::const_iterator const_iterator;
+ const_iterator begin() const { return all_hosts_.begin(); }
+ const_iterator end() const { return all_hosts_.end(); }
+
+ // Called just before |host| is destroyed so it can be de-registered
+ // from our lists.
+ void OnExtensionHostDestroyed(ExtensionHost* host);
+ private:
NotificationRegistrar registrar_;
- // The list of running viewless background extensions.
- ExtensionHostList background_hosts_;
+ // The set of all ExtensionHosts managed by this process manager.
+ ExtensionHostSet all_hosts_;
+
+ // The set of running viewless background extensions.
+ ExtensionHostSet background_hosts_;
// The BrowsingInstance shared by all extensions in this profile. This
// controls process grouping.
diff --git a/chrome/browser/extensions/extension_view_unittest.cc b/chrome/browser/extensions/extension_view_unittest.cc
index da4374e..6b35eac 100644
--- a/chrome/browser/extensions/extension_view_unittest.cc
+++ b/chrome/browser/extensions/extension_view_unittest.cc
@@ -35,7 +35,7 @@ class MockExtensionHost : public ExtensionHost {
public:
MockExtensionHost(Extension* extension, const GURL& url,
SiteInstance* instance)
- : ExtensionHost(extension, instance),
+ : ExtensionHost(extension, instance, NULL),
got_message_(false) {
CreateRenderView(url, NULL);
MessageLoop::current()->PostDelayedTask(FROM_HERE,
diff --git a/chrome/browser/tab_contents/tab_contents.h b/chrome/browser/tab_contents/tab_contents.h
index dedcca5..522f44d 100644
--- a/chrome/browser/tab_contents/tab_contents.h
+++ b/chrome/browser/tab_contents/tab_contents.h
@@ -136,6 +136,11 @@ class TabContents : public PageNavigator,
// to the actual URL that will be used. It can be modified as needed.
bool SupportsURL(GURL* url);
+ // Returns true if contains content rendered by an extension.
+ bool HostsExtension() const {
+ return render_view_host()->extension_function_dispatcher() != NULL;
+ }
+
// Returns the AutofillManager, creating it if necessary.
AutofillManager* GetAutofillManager();
diff --git a/chrome/browser/task_manager.cc b/chrome/browser/task_manager.cc
index de6f47f..f11a91a 100644
--- a/chrome/browser/task_manager.cc
+++ b/chrome/browser/task_manager.cc
@@ -60,6 +60,10 @@ TaskManagerModel::TaskManagerModel(TaskManager* task_manager)
new TaskManagerChildProcessResourceProvider(task_manager);
child_process_provider->AddRef();
providers_.push_back(child_process_provider);
+ TaskManagerExtensionProcessResourceProvider* extension_process_provider =
+ new TaskManagerExtensionProcessResourceProvider(task_manager);
+ extension_process_provider->AddRef();
+ providers_.push_back(extension_process_provider);
}
TaskManagerModel::~TaskManagerModel() {
diff --git a/chrome/browser/task_manager_resource_providers.cc b/chrome/browser/task_manager_resource_providers.cc
index 585da67..3007996 100644
--- a/chrome/browser/task_manager_resource_providers.cc
+++ b/chrome/browser/task_manager_resource_providers.cc
@@ -24,11 +24,15 @@
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_list.h"
+#include "chrome/browser/extensions/extension_host.h"
+#include "chrome/browser/extensions/extension_process_manager.h"
+#include "chrome/browser/profile_manager.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/resource_message_filter.h"
#include "chrome/browser/tab_contents/tab_util.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/child_process_host.h"
+#include "chrome/common/extensions/extension.h"
#include "chrome/common/notification_service.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
@@ -137,8 +141,11 @@ void TaskManagerTabContentsResourceProvider::StartUpdating() {
for (TabContentsIterator iterator; !iterator.done(); iterator++) {
TabContents* tab_contents = *iterator;
// Don't add dead tabs or tabs that haven't yet connected.
+ // Also ignore tabs which display extension content. We collapse
+ // all of these into one extension row.
if (tab_contents->process()->process().handle() &&
- tab_contents->notify_disconnection())
+ tab_contents->notify_disconnection() &&
+ !tab_contents->HostsExtension())
AddToTaskManager(tab_contents);
}
// Then we register for notifications to get new tabs.
@@ -154,7 +161,6 @@ void TaskManagerTabContentsResourceProvider::StartUpdating() {
// (http://crbug.com/7321).
registrar_.Add(this, NotificationType::TAB_CONTENTS_DESTROYED,
NotificationService::AllSources());
-
}
void TaskManagerTabContentsResourceProvider::StopUpdating() {
@@ -448,6 +454,122 @@ void TaskManagerChildProcessResourceProvider::ChildProcessInfoRetreived() {
}
////////////////////////////////////////////////////////////////////////////////
+// TaskManagerExtensionProcessResource class
+////////////////////////////////////////////////////////////////////////////////
+
+SkBitmap* TaskManagerExtensionProcessResource::default_icon_ = NULL;
+
+TaskManagerExtensionProcessResource::TaskManagerExtensionProcessResource(
+ ExtensionHost* extension_host)
+ : extension_host_(extension_host) {
+ if (!default_icon_) {
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ default_icon_ = rb.GetBitmapNamed(IDR_PLUGIN);
+ }
+ base::Process process(extension_host_->render_process_host()->process());
+ process_handle_ = process.handle();
+ pid_ = process.pid();
+ std::wstring extension_name(UTF8ToWide(extension()->name()));
+ DCHECK(!extension_name.empty());
+ // Since the extension_name will be concatenated with a prefix, we need
+ // to explicitly set the extension_name to be LTR format if there is no
+ // strong RTL charater in it. Otherwise, if the prefix is an RTL word,
+ // the concatenated result might be wrong. For extension named
+ // "Great Extension!" the concatenated result would be something like
+ // "!Great Extension :NOISNETXE", in which capital letters "NOISNETXE"
+ // stand for the Hebrew word for "extension".
+ l10n_util::AdjustStringForLocaleDirection(extension_name, &extension_name);
+ title_ = l10n_util::GetStringF(IDS_TASK_MANAGER_EXTENSION_PREFIX,
+ extension_name);
+}
+
+TaskManagerExtensionProcessResource::~TaskManagerExtensionProcessResource() {
+}
+
+std::wstring TaskManagerExtensionProcessResource::GetTitle() const {
+ return title_;
+}
+
+SkBitmap TaskManagerExtensionProcessResource::GetIcon() const {
+ return *default_icon_;
+}
+
+base::ProcessHandle TaskManagerExtensionProcessResource::GetProcess() const {
+ return process_handle_;
+}
+
+Extension* TaskManagerExtensionProcessResource::extension() const {
+ return extension_host_->extension();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// TaskManagerExtensionProcessResourceProvider class
+////////////////////////////////////////////////////////////////////////////////
+
+TaskManagerExtensionProcessResourceProvider::
+ TaskManagerExtensionProcessResourceProvider(TaskManager* task_manager)
+ : task_manager_(task_manager),
+ updating_(false) {
+}
+
+TaskManagerExtensionProcessResourceProvider::
+ ~TaskManagerExtensionProcessResourceProvider() {
+}
+
+TaskManager::Resource* TaskManagerExtensionProcessResourceProvider::GetResource(
+ int origin_pid,
+ int render_process_host_id,
+ int routing_id) {
+ std::map<int, TaskManagerExtensionProcessResource*>::iterator iter =
+ pid_to_resources_.find(origin_pid);
+ if (iter != pid_to_resources_.end())
+ return iter->second;
+ else
+ return NULL;
+}
+
+void TaskManagerExtensionProcessResourceProvider::StartUpdating() {
+ DCHECK(!updating_);
+ updating_ = true;
+ // Add all the existing ExtensionHosts.
+ ProfileManager* profile_manager = g_browser_process->profile_manager();
+ for (ProfileManager::const_iterator it = profile_manager->begin();
+ it != profile_manager->end(); ++it) {
+ ExtensionProcessManager* process_manager =
+ (*it)->GetExtensionProcessManager();
+ ExtensionProcessManager::const_iterator jt;
+ for (jt = process_manager->begin(); jt != process_manager->end(); ++jt)
+ AddToTaskManager(*jt);
+ }
+ // TODO(phajdan.jr): Also look for TabContents which are displaying
+ // extension content to aggregate network usage.
+ // TODO(phajdan.jr): Register for notifications.
+}
+
+void TaskManagerExtensionProcessResourceProvider::StopUpdating() {
+ DCHECK(updating_);
+ updating_ = false;
+
+ // TODO(phajdan.jr): Unregister notifications.
+
+ // Delete all the resources.
+ STLDeleteContainerPairSecondPointers(resources_.begin(), resources_.end());
+
+ resources_.clear();
+ pid_to_resources_.clear();
+}
+
+void TaskManagerExtensionProcessResourceProvider::AddToTaskManager(
+ ExtensionHost* extension_host) {
+ TaskManagerExtensionProcessResource* resource =
+ new TaskManagerExtensionProcessResource(extension_host);
+ DCHECK(resources_.find(extension_host) == resources_.end());
+ resources_[extension_host] = resource;
+ pid_to_resources_[resource->process_id()] = resource;
+ task_manager_->AddResource(resource);
+}
+
+////////////////////////////////////////////////////////////////////////////////
// TaskManagerBrowserProcessResource class
////////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/browser/task_manager_resource_providers.h b/chrome/browser/task_manager_resource_providers.h
index 0d336a0..d0e9426 100644
--- a/chrome/browser/task_manager_resource_providers.h
+++ b/chrome/browser/task_manager_resource_providers.h
@@ -5,12 +5,17 @@
#ifndef CHROME_BROWSER_TASK_MANAGER_RESOURCE_PROVIDERS_H_
#define CHROME_BROWSER_TASK_MANAGER_RESOURCE_PROVIDERS_H_
+#include <map>
+#include <vector>
+
#include "base/basictypes.h"
#include "base/process_util.h"
#include "chrome/browser/task_manager.h"
#include "chrome/common/child_process_info.h"
#include "chrome/common/notification_observer.h"
+class Extension;
+class ExtensionHost;
class TabContents;
// These file contains the resource providers used in the task manager.
@@ -28,7 +33,7 @@ class TaskManagerTabContentsResource : public TaskManager::Resource {
// TabContents always provide the network usage.
bool SupportNetworkUsage() const { return true; }
- void SetSupportNetworkUsage() { };
+ void SetSupportNetworkUsage() { }
private:
TabContents* tab_contents_;
@@ -106,7 +111,7 @@ class TaskManagerChildProcessResource : public TaskManager::Resource {
bool network_usage_support_;
// The icon painted for the child processs.
- // TODO (jcampan): we should have plugin specific icons for well-known
+ // TODO(jcampan): we should have plugin specific icons for well-known
// plugins.
static SkBitmap* default_icon_;
@@ -168,6 +173,67 @@ class TaskManagerChildProcessResourceProvider
DISALLOW_COPY_AND_ASSIGN(TaskManagerChildProcessResourceProvider);
};
+class TaskManagerExtensionProcessResource : public TaskManager::Resource {
+ public:
+ explicit TaskManagerExtensionProcessResource(ExtensionHost* extension_host);
+ ~TaskManagerExtensionProcessResource();
+
+ // TaskManagerResource methods:
+ std::wstring GetTitle() const;
+ SkBitmap GetIcon() const;
+ base::ProcessHandle GetProcess() const;
+ bool SupportNetworkUsage() const { return true; }
+ void SetSupportNetworkUsage() { NOTREACHED(); }
+
+ // Returns the pid of the extension process.
+ int process_id() const { return pid_; }
+
+ private:
+ Extension* extension() const;
+
+ // The icon painted for the extension process.
+ static SkBitmap* default_icon_;
+
+ ExtensionHost* extension_host_;
+
+ // Cached data about the extension.
+ base::ProcessHandle process_handle_;
+ int pid_;
+ std::wstring title_;
+
+ DISALLOW_COPY_AND_ASSIGN(TaskManagerExtensionProcessResource);
+};
+
+class TaskManagerExtensionProcessResourceProvider
+ : public TaskManager::ResourceProvider {
+ public:
+ explicit TaskManagerExtensionProcessResourceProvider(
+ TaskManager* task_manager);
+ virtual ~TaskManagerExtensionProcessResourceProvider();
+
+ virtual TaskManager::Resource* GetResource(int origin_pid,
+ int render_process_host_id,
+ int routing_id);
+ virtual void StartUpdating();
+ virtual void StopUpdating();
+
+ private:
+ void AddToTaskManager(ExtensionHost* extension_host);
+
+ TaskManager* task_manager_;
+
+ // Maps the actual resources (ExtensionHost*) to the Task Manager resources.
+ std::map<ExtensionHost*, TaskManagerExtensionProcessResource*> resources_;
+
+ // Maps the pids to the resources (used for quick access to the resource on
+ // byte read notifications).
+ std::map<int, TaskManagerExtensionProcessResource*> pid_to_resources_;
+
+ bool updating_;
+
+ DISALLOW_COPY_AND_ASSIGN(TaskManagerExtensionProcessResourceProvider);
+};
+
class TaskManagerBrowserProcessResource : public TaskManager::Resource {
public:
TaskManagerBrowserProcessResource();