diff options
author | phajdan.jr@chromium.org <phajdan.jr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-06 08:19:49 +0000 |
---|---|---|
committer | phajdan.jr@chromium.org <phajdan.jr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-06 08:19:49 +0000 |
commit | 8a17bd55d6f0336a3d8e3c66af61a0a3b074dfe9 (patch) | |
tree | c46ba5bfb499017b07cacdb6f8665070e77bbb3a /chrome | |
parent | 31e8a0105e34d04ec14a5387b907b90a776d82f5 (diff) | |
download | chromium_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.grd | 3 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_host.cc | 11 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_host.h | 11 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_process_manager.cc | 28 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_process_manager.h | 22 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_view_unittest.cc | 2 | ||||
-rw-r--r-- | chrome/browser/tab_contents/tab_contents.h | 5 | ||||
-rw-r--r-- | chrome/browser/task_manager.cc | 4 | ||||
-rw-r--r-- | chrome/browser/task_manager_resource_providers.cc | 126 | ||||
-rw-r--r-- | chrome/browser/task_manager_resource_providers.h | 70 |
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(); |