Home | History | Annotate | Download | only in task_manager
      1 // Copyright 2013 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/task_manager/extension_process_resource_provider.h"
      6 
      7 #include "base/strings/string16.h"
      8 #include "base/strings/utf_string_conversions.h"
      9 #include "chrome/browser/browser_process.h"
     10 #include "chrome/browser/chrome_notification_types.h"
     11 #include "chrome/browser/devtools/devtools_window.h"
     12 #include "chrome/browser/extensions/extension_host.h"
     13 #include "chrome/browser/extensions/extension_process_manager.h"
     14 #include "chrome/browser/extensions/extension_system.h"
     15 #include "chrome/browser/profiles/profile.h"
     16 #include "chrome/browser/profiles/profile_manager.h"
     17 #include "chrome/browser/task_manager/resource_provider.h"
     18 #include "chrome/browser/task_manager/task_manager.h"
     19 #include "chrome/browser/task_manager/task_manager_util.h"
     20 #include "chrome/common/extensions/extension.h"
     21 #include "content/public/browser/notification_details.h"
     22 #include "content/public/browser/notification_service.h"
     23 #include "content/public/browser/render_process_host.h"
     24 #include "content/public/browser/render_view_host.h"
     25 #include "content/public/browser/site_instance.h"
     26 #include "content/public/browser/web_contents.h"
     27 #include "extensions/browser/view_type_utils.h"
     28 #include "grit/theme_resources.h"
     29 #include "ui/base/l10n/l10n_util.h"
     30 #include "ui/base/resource/resource_bundle.h"
     31 #include "ui/gfx/image/image_skia.h"
     32 
     33 using content::WebContents;
     34 using extensions::Extension;
     35 
     36 namespace task_manager {
     37 
     38 class ExtensionProcessResource : public Resource {
     39  public:
     40   explicit ExtensionProcessResource(
     41       content::RenderViewHost* render_view_host);
     42   virtual ~ExtensionProcessResource();
     43 
     44   // Resource methods:
     45   virtual string16 GetTitle() const OVERRIDE;
     46   virtual string16 GetProfileName() const OVERRIDE;
     47   virtual gfx::ImageSkia GetIcon() const OVERRIDE;
     48   virtual base::ProcessHandle GetProcess() const OVERRIDE;
     49   virtual int GetUniqueChildProcessId() const OVERRIDE;
     50   virtual Type GetType() const OVERRIDE;
     51   virtual bool CanInspect() const OVERRIDE;
     52   virtual void Inspect() const OVERRIDE;
     53   virtual bool SupportNetworkUsage() const OVERRIDE;
     54   virtual void SetSupportNetworkUsage() OVERRIDE;
     55   virtual const extensions::Extension* GetExtension() const OVERRIDE;
     56 
     57   // Returns the pid of the extension process.
     58   int process_id() const { return pid_; }
     59 
     60   // Returns true if the associated extension has a background page.
     61   virtual bool IsBackground() const OVERRIDE;
     62 
     63  private:
     64   // The icon painted for the extension process.
     65   static gfx::ImageSkia* default_icon_;
     66 
     67   content::RenderViewHost* render_view_host_;
     68 
     69   // Cached data about the extension.
     70   base::ProcessHandle process_handle_;
     71   int pid_;
     72   int unique_process_id_;
     73   string16 title_;
     74 
     75   DISALLOW_COPY_AND_ASSIGN(ExtensionProcessResource);
     76 };
     77 
     78 gfx::ImageSkia* ExtensionProcessResource::default_icon_ = NULL;
     79 
     80 ExtensionProcessResource::ExtensionProcessResource(
     81     content::RenderViewHost* render_view_host)
     82     : render_view_host_(render_view_host) {
     83   if (!default_icon_) {
     84     ResourceBundle& rb = ResourceBundle::GetSharedInstance();
     85     default_icon_ = rb.GetImageSkiaNamed(IDR_PLUGINS_FAVICON);
     86   }
     87   process_handle_ = render_view_host_->GetProcess()->GetHandle();
     88   unique_process_id_ = render_view_host->GetProcess()->GetID();
     89   pid_ = base::GetProcId(process_handle_);
     90   string16 extension_name = UTF8ToUTF16(GetExtension()->name());
     91   DCHECK(!extension_name.empty());
     92 
     93   Profile* profile = Profile::FromBrowserContext(
     94       render_view_host->GetProcess()->GetBrowserContext());
     95   int message_id = util::GetMessagePrefixID(
     96       GetExtension()->is_app(),
     97       true,  // is_extension
     98       profile->IsOffTheRecord(),
     99       false,  // is_prerender
    100       false,  // is_instant_overlay
    101       IsBackground());
    102   title_ = l10n_util::GetStringFUTF16(message_id, extension_name);
    103 }
    104 
    105 ExtensionProcessResource::~ExtensionProcessResource() {
    106 }
    107 
    108 string16 ExtensionProcessResource::GetTitle() const {
    109   return title_;
    110 }
    111 
    112 string16 ExtensionProcessResource::GetProfileName() const {
    113   return util::GetProfileNameFromInfoCache(
    114       Profile::FromBrowserContext(
    115           render_view_host_->GetProcess()->GetBrowserContext()));
    116 }
    117 
    118 gfx::ImageSkia ExtensionProcessResource::GetIcon() const {
    119   return *default_icon_;
    120 }
    121 
    122 base::ProcessHandle ExtensionProcessResource::GetProcess() const {
    123   return process_handle_;
    124 }
    125 
    126 int ExtensionProcessResource::GetUniqueChildProcessId() const {
    127   return unique_process_id_;
    128 }
    129 
    130 Resource::Type ExtensionProcessResource::GetType() const {
    131   return EXTENSION;
    132 }
    133 
    134 bool ExtensionProcessResource::CanInspect() const {
    135   return true;
    136 }
    137 
    138 void ExtensionProcessResource::Inspect() const {
    139   DevToolsWindow::OpenDevToolsWindow(render_view_host_);
    140 }
    141 
    142 bool ExtensionProcessResource::SupportNetworkUsage() const {
    143   return true;
    144 }
    145 
    146 void ExtensionProcessResource::SetSupportNetworkUsage() {
    147   NOTREACHED();
    148 }
    149 
    150 const Extension* ExtensionProcessResource::GetExtension() const {
    151   Profile* profile = Profile::FromBrowserContext(
    152       render_view_host_->GetProcess()->GetBrowserContext());
    153   ExtensionProcessManager* process_manager =
    154       extensions::ExtensionSystem::Get(profile)->process_manager();
    155   return process_manager->GetExtensionForRenderViewHost(render_view_host_);
    156 }
    157 
    158 bool ExtensionProcessResource::IsBackground() const {
    159   WebContents* web_contents =
    160       WebContents::FromRenderViewHost(render_view_host_);
    161   extensions::ViewType view_type = extensions::GetViewType(web_contents);
    162   return view_type == extensions::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE;
    163 }
    164 
    165 ////////////////////////////////////////////////////////////////////////////////
    166 // ExtensionProcessResourceProvider class
    167 ////////////////////////////////////////////////////////////////////////////////
    168 
    169 ExtensionProcessResourceProvider::
    170     ExtensionProcessResourceProvider(TaskManager* task_manager)
    171     : task_manager_(task_manager),
    172       updating_(false) {
    173 }
    174 
    175 ExtensionProcessResourceProvider::~ExtensionProcessResourceProvider() {
    176 }
    177 
    178 Resource* ExtensionProcessResourceProvider::GetResource(
    179     int origin_pid,
    180     int render_process_host_id,
    181     int routing_id) {
    182   // If an origin PID was specified, the request is from a plugin, not the
    183   // render view host process
    184   if (origin_pid)
    185     return NULL;
    186 
    187   for (ExtensionRenderViewHostMap::iterator i = resources_.begin();
    188        i != resources_.end(); i++) {
    189     if (i->first->GetSiteInstance()->GetProcess()->GetID() ==
    190             render_process_host_id &&
    191         i->first->GetRoutingID() == routing_id)
    192       return i->second;
    193   }
    194 
    195   // Can happen if the page went away while a network request was being
    196   // performed.
    197   return NULL;
    198 }
    199 
    200 void ExtensionProcessResourceProvider::StartUpdating() {
    201   DCHECK(!updating_);
    202   updating_ = true;
    203 
    204   // Add all the existing extension views from all Profiles, including those
    205   // from incognito split mode.
    206   ProfileManager* profile_manager = g_browser_process->profile_manager();
    207   std::vector<Profile*> profiles(profile_manager->GetLoadedProfiles());
    208   size_t num_default_profiles = profiles.size();
    209   for (size_t i = 0; i < num_default_profiles; ++i) {
    210     if (profiles[i]->HasOffTheRecordProfile()) {
    211       profiles.push_back(profiles[i]->GetOffTheRecordProfile());
    212     }
    213   }
    214 
    215   for (size_t i = 0; i < profiles.size(); ++i) {
    216     ExtensionProcessManager* process_manager =
    217         extensions::ExtensionSystem::Get(profiles[i])->process_manager();
    218     if (process_manager) {
    219       const ExtensionProcessManager::ViewSet all_views =
    220           process_manager->GetAllViews();
    221       ExtensionProcessManager::ViewSet::const_iterator jt = all_views.begin();
    222       for (; jt != all_views.end(); ++jt) {
    223         content::RenderViewHost* rvh = *jt;
    224         // Don't add dead extension processes.
    225         if (!rvh->IsRenderViewLive())
    226           continue;
    227 
    228         AddToTaskManager(rvh);
    229       }
    230     }
    231   }
    232 
    233   // Register for notifications about extension process changes.
    234   registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_VIEW_REGISTERED,
    235                  content::NotificationService::AllBrowserContextsAndSources());
    236   registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_PROCESS_TERMINATED,
    237                  content::NotificationService::AllBrowserContextsAndSources());
    238   registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_VIEW_UNREGISTERED,
    239                  content::NotificationService::AllBrowserContextsAndSources());
    240 }
    241 
    242 void ExtensionProcessResourceProvider::StopUpdating() {
    243   DCHECK(updating_);
    244   updating_ = false;
    245 
    246   // Unregister for notifications about extension process changes.
    247   registrar_.Remove(
    248       this, chrome::NOTIFICATION_EXTENSION_VIEW_REGISTERED,
    249       content::NotificationService::AllBrowserContextsAndSources());
    250   registrar_.Remove(
    251       this, chrome::NOTIFICATION_EXTENSION_PROCESS_TERMINATED,
    252       content::NotificationService::AllBrowserContextsAndSources());
    253   registrar_.Remove(
    254       this, chrome::NOTIFICATION_EXTENSION_VIEW_UNREGISTERED,
    255       content::NotificationService::AllBrowserContextsAndSources());
    256 
    257   // Delete all the resources.
    258   STLDeleteContainerPairSecondPointers(resources_.begin(), resources_.end());
    259 
    260   resources_.clear();
    261 }
    262 
    263 void ExtensionProcessResourceProvider::Observe(
    264     int type,
    265     const content::NotificationSource& source,
    266     const content::NotificationDetails& details) {
    267   switch (type) {
    268     case chrome::NOTIFICATION_EXTENSION_VIEW_REGISTERED:
    269       AddToTaskManager(
    270           content::Details<content::RenderViewHost>(details).ptr());
    271       break;
    272     case chrome::NOTIFICATION_EXTENSION_PROCESS_TERMINATED:
    273       RemoveFromTaskManager(
    274           content::Details<extensions::ExtensionHost>(details).ptr()->
    275           render_view_host());
    276       break;
    277     case chrome::NOTIFICATION_EXTENSION_VIEW_UNREGISTERED:
    278       RemoveFromTaskManager(
    279           content::Details<content::RenderViewHost>(details).ptr());
    280       break;
    281     default:
    282       NOTREACHED() << "Unexpected notification.";
    283       return;
    284   }
    285 }
    286 
    287 bool ExtensionProcessResourceProvider::
    288     IsHandledByThisProvider(content::RenderViewHost* render_view_host) {
    289   WebContents* web_contents = WebContents::FromRenderViewHost(render_view_host);
    290   // Don't add WebContents that belong to a guest (those are handled by
    291   // GuestResourceProvider). Otherwise they will be added twice, and
    292   // in this case they will have the app's name as a title (due to the
    293   // ExtensionProcessResource constructor).
    294   if (web_contents->GetRenderProcessHost()->IsGuest())
    295     return false;
    296   extensions::ViewType view_type = extensions::GetViewType(web_contents);
    297   // Don't add WebContents (those are handled by
    298   // TabContentsResourceProvider) or background contents (handled
    299   // by BackgroundResourceProvider).
    300 #if defined(USE_ASH)
    301   return (view_type != extensions::VIEW_TYPE_TAB_CONTENTS &&
    302           view_type != extensions::VIEW_TYPE_BACKGROUND_CONTENTS);
    303 #else
    304   return (view_type != extensions::VIEW_TYPE_TAB_CONTENTS &&
    305           view_type != extensions::VIEW_TYPE_BACKGROUND_CONTENTS &&
    306           view_type != extensions::VIEW_TYPE_PANEL);
    307 #endif  // USE_ASH
    308 }
    309 
    310 void ExtensionProcessResourceProvider::AddToTaskManager(
    311     content::RenderViewHost* render_view_host) {
    312   if (!IsHandledByThisProvider(render_view_host))
    313     return;
    314 
    315   ExtensionProcessResource* resource =
    316       new ExtensionProcessResource(render_view_host);
    317   DCHECK(resources_.find(render_view_host) == resources_.end());
    318   resources_[render_view_host] = resource;
    319   task_manager_->AddResource(resource);
    320 }
    321 
    322 void ExtensionProcessResourceProvider::RemoveFromTaskManager(
    323     content::RenderViewHost* render_view_host) {
    324   if (!updating_)
    325     return;
    326   std::map<content::RenderViewHost*, ExtensionProcessResource*>
    327       ::iterator iter = resources_.find(render_view_host);
    328   if (iter == resources_.end())
    329     return;
    330 
    331   // Remove the resource from the Task Manager.
    332   ExtensionProcessResource* resource = iter->second;
    333   task_manager_->RemoveResource(resource);
    334 
    335   // Remove it from the provider.
    336   resources_.erase(iter);
    337 
    338   // Finally, delete the resource.
    339   delete resource;
    340 }
    341 
    342 }  // namespace task_manager
    343