Home | History | Annotate | Download | only in task_manager
      1 // Copyright (c) 2011 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/task_manager_resource_providers.h"
      6 
      7 #include "base/basictypes.h"
      8 #include "base/file_version_info.h"
      9 #include "base/i18n/rtl.h"
     10 #include "base/process_util.h"
     11 #include "base/stl_util-inl.h"
     12 #include "base/string_util.h"
     13 #include "base/threading/thread.h"
     14 #include "base/utf_string_conversions.h"
     15 #include "build/build_config.h"
     16 #include "chrome/app/chrome_command_ids.h"
     17 #include "chrome/browser/background_contents_service.h"
     18 #include "chrome/browser/background_contents_service_factory.h"
     19 #include "chrome/browser/browser_process.h"
     20 #include "chrome/browser/extensions/extension_host.h"
     21 #include "chrome/browser/extensions/extension_process_manager.h"
     22 #include "chrome/browser/extensions/extension_service.h"
     23 #include "chrome/browser/notifications/balloon_collection.h"
     24 #include "chrome/browser/notifications/balloon_host.h"
     25 #include "chrome/browser/notifications/notification_ui_manager.h"
     26 #include "chrome/browser/prerender/prerender_contents.h"
     27 #include "chrome/browser/prerender/prerender_manager.h"
     28 #include "chrome/browser/profiles/profile_manager.h"
     29 #include "chrome/browser/tab_contents/background_contents.h"
     30 #include "chrome/browser/tab_contents/tab_util.h"
     31 #include "chrome/browser/ui/browser_list.h"
     32 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
     33 #include "chrome/common/extensions/extension.h"
     34 #include "chrome/common/render_messages.h"
     35 #include "content/browser/browser_child_process_host.h"
     36 #include "content/browser/browser_thread.h"
     37 #include "content/browser/renderer_host/render_message_filter.h"
     38 #include "content/browser/renderer_host/render_process_host.h"
     39 #include "content/browser/renderer_host/render_view_host.h"
     40 #include "content/browser/tab_contents/tab_contents.h"
     41 #include "content/common/notification_service.h"
     42 #include "grit/generated_resources.h"
     43 #include "grit/theme_resources.h"
     44 #include "third_party/sqlite/sqlite3.h"
     45 #include "ui/base/l10n/l10n_util.h"
     46 #include "ui/base/resource/resource_bundle.h"
     47 
     48 #if defined(OS_MACOSX)
     49 #include "skia/ext/skia_utils_mac.h"
     50 #endif
     51 #if defined(OS_WIN)
     52 #include "chrome/browser/app_icon_win.h"
     53 #include "ui/gfx/icon_util.h"
     54 #endif  // defined(OS_WIN)
     55 
     56 namespace {
     57 
     58 // Returns the appropriate message prefix ID for tabs and extensions,
     59 // reflecting whether they are apps or in incognito mode.
     60 int GetMessagePrefixID(bool is_app, bool is_extension,
     61                        bool is_incognito) {
     62   return is_app ?
     63       (is_incognito ?
     64           IDS_TASK_MANAGER_APP_INCOGNITO_PREFIX :
     65           IDS_TASK_MANAGER_APP_PREFIX) :
     66       (is_extension ?
     67           (is_incognito ?
     68               IDS_TASK_MANAGER_EXTENSION_INCOGNITO_PREFIX :
     69               IDS_TASK_MANAGER_EXTENSION_PREFIX) :
     70           IDS_TASK_MANAGER_TAB_PREFIX);
     71 }
     72 
     73 }  // namespace
     74 
     75 ////////////////////////////////////////////////////////////////////////////////
     76 // TaskManagerRendererResource class
     77 ////////////////////////////////////////////////////////////////////////////////
     78 TaskManagerRendererResource::TaskManagerRendererResource(
     79     base::ProcessHandle process, RenderViewHost* render_view_host)
     80     : process_(process),
     81       render_view_host_(render_view_host),
     82       pending_stats_update_(false),
     83       v8_memory_allocated_(0),
     84       v8_memory_used_(0),
     85       pending_v8_memory_allocated_update_(false) {
     86   // We cache the process and pid as when a Tab/BackgroundContents is closed the
     87   // process reference becomes NULL and the TaskManager still needs it.
     88   pid_ = base::GetProcId(process_);
     89   stats_.images.size = 0;
     90   stats_.cssStyleSheets.size = 0;
     91   stats_.scripts.size = 0;
     92   stats_.xslStyleSheets.size = 0;
     93   stats_.fonts.size = 0;
     94 }
     95 
     96 TaskManagerRendererResource::~TaskManagerRendererResource() {
     97 }
     98 
     99 void TaskManagerRendererResource::Refresh() {
    100   if (!pending_stats_update_) {
    101     render_view_host_->Send(new ViewMsg_GetCacheResourceStats);
    102     pending_stats_update_ = true;
    103   }
    104   if (!pending_v8_memory_allocated_update_) {
    105     render_view_host_->Send(new ViewMsg_GetV8HeapStats);
    106     pending_v8_memory_allocated_update_ = true;
    107   }
    108 }
    109 
    110 WebKit::WebCache::ResourceTypeStats
    111 TaskManagerRendererResource::GetWebCoreCacheStats() const {
    112   return stats_;
    113 }
    114 
    115 size_t TaskManagerRendererResource::GetV8MemoryAllocated() const {
    116   return v8_memory_allocated_;
    117 }
    118 
    119 size_t TaskManagerRendererResource::GetV8MemoryUsed() const {
    120   return v8_memory_used_;
    121 }
    122 
    123 void TaskManagerRendererResource::NotifyResourceTypeStats(
    124     const WebKit::WebCache::ResourceTypeStats& stats) {
    125   stats_ = stats;
    126   pending_stats_update_ = false;
    127 }
    128 
    129 void TaskManagerRendererResource::NotifyV8HeapStats(
    130     size_t v8_memory_allocated, size_t v8_memory_used) {
    131   v8_memory_allocated_ = v8_memory_allocated;
    132   v8_memory_used_ = v8_memory_used;
    133   pending_v8_memory_allocated_update_ = false;
    134 }
    135 
    136 base::ProcessHandle TaskManagerRendererResource::GetProcess() const {
    137   return process_;
    138 }
    139 
    140 TaskManager::Resource::Type TaskManagerRendererResource::GetType() const {
    141   return RENDERER;
    142 }
    143 
    144 bool TaskManagerRendererResource::ReportsCacheStats() const {
    145   return true;
    146 }
    147 
    148 bool TaskManagerRendererResource::ReportsV8MemoryStats() const {
    149   return true;
    150 }
    151 
    152 bool TaskManagerRendererResource::SupportNetworkUsage() const {
    153   return true;
    154 }
    155 
    156 ////////////////////////////////////////////////////////////////////////////////
    157 // TaskManagerTabContentsResource class
    158 ////////////////////////////////////////////////////////////////////////////////
    159 
    160 TaskManagerTabContentsResource::TaskManagerTabContentsResource(
    161     TabContentsWrapper* tab_contents)
    162     : TaskManagerRendererResource(
    163           tab_contents->tab_contents()->GetRenderProcessHost()->GetHandle(),
    164           tab_contents->render_view_host()),
    165       tab_contents_(tab_contents) {
    166 }
    167 
    168 TaskManagerTabContentsResource::~TaskManagerTabContentsResource() {
    169 }
    170 
    171 TaskManager::Resource::Type TaskManagerTabContentsResource::GetType() const {
    172   return tab_contents_->tab_contents()->HostsExtension() ? EXTENSION : RENDERER;
    173 }
    174 
    175 string16 TaskManagerTabContentsResource::GetTitle() const {
    176   // Fall back on the URL if there's no title.
    177   string16 tab_title = tab_contents_->tab_contents()->GetTitle();
    178   if (tab_title.empty()) {
    179     tab_title = UTF8ToUTF16(tab_contents_->tab_contents()->GetURL().spec());
    180     // Force URL to be LTR.
    181     tab_title = base::i18n::GetDisplayStringInLTRDirectionality(tab_title);
    182   } else {
    183     // Since the tab_title will be concatenated with
    184     // IDS_TASK_MANAGER_TAB_PREFIX, we need to explicitly set the tab_title to
    185     // be LTR format if there is no strong RTL charater in it. Otherwise, if
    186     // IDS_TASK_MANAGER_TAB_PREFIX is an RTL word, the concatenated result
    187     // might be wrong. For example, http://mail.yahoo.com, whose title is
    188     // "Yahoo! Mail: The best web-based Email!", without setting it explicitly
    189     // as LTR format, the concatenated result will be "!Yahoo! Mail: The best
    190     // web-based Email :BAT", in which the capital letters "BAT" stands for
    191     // the Hebrew word for "tab".
    192     base::i18n::AdjustStringForLocaleDirection(&tab_title);
    193   }
    194 
    195   ExtensionService* extensions_service =
    196       tab_contents_->profile()->GetExtensionService();
    197   int message_id = GetMessagePrefixID(
    198       extensions_service->IsInstalledApp(
    199           tab_contents_->tab_contents()->GetURL()),
    200       tab_contents_->tab_contents()->HostsExtension(),
    201       tab_contents_->profile()->IsOffTheRecord());
    202   return l10n_util::GetStringFUTF16(message_id, tab_title);
    203 }
    204 
    205 SkBitmap TaskManagerTabContentsResource::GetIcon() const {
    206   return tab_contents_->tab_contents()->GetFavicon();
    207 }
    208 
    209 TabContentsWrapper* TaskManagerTabContentsResource::GetTabContents() const {
    210   return tab_contents_;
    211 }
    212 
    213 const Extension* TaskManagerTabContentsResource::GetExtension() const {
    214   if (tab_contents_->tab_contents()->HostsExtension()) {
    215     ExtensionService* extensions_service =
    216         tab_contents_->profile()->GetExtensionService();
    217     return extensions_service->GetExtensionByURL(
    218         tab_contents_->tab_contents()->GetURL());
    219   }
    220 
    221   return NULL;
    222 }
    223 
    224 ////////////////////////////////////////////////////////////////////////////////
    225 // TaskManagerTabContentsResourceProvider class
    226 ////////////////////////////////////////////////////////////////////////////////
    227 
    228 TaskManagerTabContentsResourceProvider::
    229     TaskManagerTabContentsResourceProvider(TaskManager* task_manager)
    230     :  updating_(false),
    231        task_manager_(task_manager) {
    232 }
    233 
    234 TaskManagerTabContentsResourceProvider::
    235     ~TaskManagerTabContentsResourceProvider() {
    236 }
    237 
    238 TaskManager::Resource* TaskManagerTabContentsResourceProvider::GetResource(
    239     int origin_pid,
    240     int render_process_host_id,
    241     int routing_id) {
    242   TabContents* tab_contents =
    243       tab_util::GetTabContentsByID(render_process_host_id, routing_id);
    244   if (!tab_contents)  // Not one of our resource.
    245     return NULL;
    246 
    247   // If an origin PID was specified then the request originated in a plugin
    248   // working on the TabContent's behalf, so ignore it.
    249   if (origin_pid)
    250     return NULL;
    251 
    252   TabContentsWrapper* wrapper =
    253       TabContentsWrapper::GetCurrentWrapperForContents(tab_contents);
    254   std::map<TabContentsWrapper*, TaskManagerTabContentsResource*>::iterator
    255       res_iter = resources_.find(wrapper);
    256   if (res_iter == resources_.end()) {
    257     // Can happen if the tab was closed while a network request was being
    258     // performed.
    259     return NULL;
    260   }
    261   return res_iter->second;
    262 }
    263 
    264 void TaskManagerTabContentsResourceProvider::StartUpdating() {
    265   DCHECK(!updating_);
    266   updating_ = true;
    267 
    268   // Add all the existing TabContents.
    269   for (TabContentsIterator iterator; !iterator.done(); ++iterator)
    270     Add(*iterator);
    271 
    272   // Then we register for notifications to get new tabs.
    273   registrar_.Add(this, NotificationType::TAB_CONTENTS_CONNECTED,
    274                  NotificationService::AllSources());
    275   registrar_.Add(this, NotificationType::TAB_CONTENTS_SWAPPED,
    276                  NotificationService::AllSources());
    277   registrar_.Add(this, NotificationType::TAB_CONTENTS_DISCONNECTED,
    278                  NotificationService::AllSources());
    279   // TAB_CONTENTS_DISCONNECTED should be enough to know when to remove a
    280   // resource.  This is an attempt at mitigating a crasher that seem to
    281   // indicate a resource is still referencing a deleted TabContents
    282   // (http://crbug.com/7321).
    283   registrar_.Add(this, NotificationType::TAB_CONTENTS_DESTROYED,
    284                  NotificationService::AllSources());
    285 }
    286 
    287 void TaskManagerTabContentsResourceProvider::StopUpdating() {
    288   DCHECK(updating_);
    289   updating_ = false;
    290 
    291   // Then we unregister for notifications to get new tabs.
    292   registrar_.Remove(this, NotificationType::TAB_CONTENTS_CONNECTED,
    293                     NotificationService::AllSources());
    294   registrar_.Remove(this, NotificationType::TAB_CONTENTS_SWAPPED,
    295                     NotificationService::AllSources());
    296   registrar_.Remove(this, NotificationType::TAB_CONTENTS_DISCONNECTED,
    297                     NotificationService::AllSources());
    298   registrar_.Remove(this, NotificationType::TAB_CONTENTS_DESTROYED,
    299                     NotificationService::AllSources());
    300 
    301   // Delete all the resources.
    302   STLDeleteContainerPairSecondPointers(resources_.begin(), resources_.end());
    303 
    304   resources_.clear();
    305 }
    306 
    307 void TaskManagerTabContentsResourceProvider::AddToTaskManager(
    308     TabContentsWrapper* tab_contents) {
    309   TaskManagerTabContentsResource* resource =
    310       new TaskManagerTabContentsResource(tab_contents);
    311   resources_[tab_contents] = resource;
    312   task_manager_->AddResource(resource);
    313 }
    314 
    315 void TaskManagerTabContentsResourceProvider::Add(
    316     TabContentsWrapper* tab_contents) {
    317   if (!updating_)
    318     return;
    319 
    320   // Don't add dead tabs or tabs that haven't yet connected.
    321   if (!tab_contents->tab_contents()->GetRenderProcessHost()->GetHandle() ||
    322       !tab_contents->tab_contents()->notify_disconnection()) {
    323     return;
    324   }
    325 
    326   std::map<TabContentsWrapper*, TaskManagerTabContentsResource*>::const_iterator
    327       iter = resources_.find(tab_contents);
    328   if (iter != resources_.end()) {
    329     // The case may happen that we have added a TabContents as part of the
    330     // iteration performed during StartUpdating() call but the notification that
    331     // it has connected was not fired yet. So when the notification happens, we
    332     // already know about this tab and just ignore it.
    333     return;
    334   }
    335   AddToTaskManager(tab_contents);
    336 }
    337 
    338 void TaskManagerTabContentsResourceProvider::Remove(
    339     TabContentsWrapper* tab_contents) {
    340   if (!updating_)
    341     return;
    342   std::map<TabContentsWrapper*, TaskManagerTabContentsResource*>::iterator
    343       iter = resources_.find(tab_contents);
    344   if (iter == resources_.end()) {
    345     // Since TabContents are destroyed asynchronously (see TabContentsCollector
    346     // in navigation_controller.cc), we can be notified of a tab being removed
    347     // that we don't know.  This can happen if the user closes a tab and quickly
    348     // opens the task manager, before the tab is actually destroyed.
    349     return;
    350   }
    351 
    352   // Remove the resource from the Task Manager.
    353   TaskManagerTabContentsResource* resource = iter->second;
    354   task_manager_->RemoveResource(resource);
    355   // And from the provider.
    356   resources_.erase(iter);
    357   // Finally, delete the resource.
    358   delete resource;
    359 }
    360 
    361 void TaskManagerTabContentsResourceProvider::Observe(NotificationType type,
    362     const NotificationSource& source,
    363     const NotificationDetails& details) {
    364   TabContentsWrapper* tab_contents =
    365       TabContentsWrapper::GetCurrentWrapperForContents(
    366           Source<TabContents>(source).ptr());
    367   // A background page does not have a TabContentsWrapper.
    368   if (!tab_contents)
    369     return;
    370   switch (type.value) {
    371     case NotificationType::TAB_CONTENTS_CONNECTED:
    372       Add(tab_contents);
    373       break;
    374     case NotificationType::TAB_CONTENTS_SWAPPED:
    375       Remove(tab_contents);
    376       Add(tab_contents);
    377       break;
    378     case NotificationType::TAB_CONTENTS_DESTROYED:
    379       // If this DCHECK is triggered, it could explain http://crbug.com/7321 .
    380       DCHECK(resources_.find(tab_contents) ==
    381              resources_.end()) << "TAB_CONTENTS_DESTROYED with no associated "
    382                                   "TAB_CONTENTS_DISCONNECTED";
    383       // Fall through.
    384     case NotificationType::TAB_CONTENTS_DISCONNECTED:
    385       Remove(tab_contents);
    386       break;
    387     default:
    388       NOTREACHED() << "Unexpected notification.";
    389       return;
    390   }
    391 }
    392 
    393 ////////////////////////////////////////////////////////////////////////////////
    394 // TaskManagerPrerenderResource class
    395 ////////////////////////////////////////////////////////////////////////////////
    396 // static
    397 SkBitmap* TaskManagerPrerenderResource::default_icon_ = NULL;
    398 
    399 TaskManagerPrerenderResource::TaskManagerPrerenderResource(
    400     RenderViewHost* render_view_host)
    401     : TaskManagerRendererResource(
    402           render_view_host->process()->GetHandle(),
    403           render_view_host),
    404       process_route_id_pair_(std::make_pair(render_view_host->process()->id(),
    405                                             render_view_host->routing_id())) {
    406   if (!default_icon_) {
    407     ResourceBundle& rb = ResourceBundle::GetSharedInstance();
    408     default_icon_ = rb.GetBitmapNamed(IDR_PRERENDER);
    409   }
    410 }
    411 
    412 TaskManagerPrerenderResource::~TaskManagerPrerenderResource() {
    413 }
    414 
    415 TaskManager::Resource::Type TaskManagerPrerenderResource::GetType() const {
    416   return RENDERER;
    417 }
    418 
    419 string16 TaskManagerPrerenderResource::GetTitle() const {
    420   // The URL is used as the title.
    421   // TODO(dominich): Expose document title through RenderHostDelegate.
    422   // http://crbug.com/77776
    423   RenderViewHost* render_view_host =
    424       RenderViewHost::FromID(process_route_id_pair_.first,
    425                              process_route_id_pair_.second);
    426 
    427   // In some instances, for instance when the RenderProcessHost has been
    428   // destroyed, we try to get the title for a RenderViewHost that has
    429   // been removed. Return an empty string in this case.
    430   if (!render_view_host)
    431     return EmptyString16();
    432 
    433   RenderViewHostDelegate* delegate = render_view_host->delegate();
    434 
    435   string16 title = UTF8ToUTF16(delegate->GetURL().spec());
    436   // Force URL to be LTR.
    437   title = base::i18n::GetDisplayStringInLTRDirectionality(title);
    438 
    439   int message_id = IDS_TASK_MANAGER_PRERENDER_PREFIX;
    440   return l10n_util::GetStringFUTF16(message_id, title);
    441 }
    442 
    443 SkBitmap TaskManagerPrerenderResource::GetIcon() const {
    444   // TODO(dominich): use the favicon if available.
    445   // http://crbug.com/77782
    446   return *default_icon_;
    447 }
    448 
    449 ////////////////////////////////////////////////////////////////////////////////
    450 // TaskManagerPrerenderResourceProvider class
    451 ////////////////////////////////////////////////////////////////////////////////
    452 
    453 TaskManagerPrerenderResourceProvider::TaskManagerPrerenderResourceProvider(
    454     TaskManager* task_manager)
    455     :  updating_(false),
    456        task_manager_(task_manager) {
    457 }
    458 
    459 TaskManagerPrerenderResourceProvider::~TaskManagerPrerenderResourceProvider() {
    460   STLDeleteContainerPairSecondPointers(resources_.begin(), resources_.end());
    461 }
    462 
    463 TaskManager::Resource* TaskManagerPrerenderResourceProvider::GetResource(
    464     int origin_pid,
    465     int render_process_host_id,
    466     int routing_id) {
    467   // If an origin PID was specified then the request originated in a plugin so
    468   // ignore it.
    469   if (origin_pid)
    470     return NULL;
    471 
    472   ResourceMap::iterator res_iter = resources_.find(
    473       std::make_pair(render_process_host_id, routing_id));
    474   if (res_iter == resources_.end())
    475     return NULL;
    476 
    477   return res_iter->second;
    478 }
    479 
    480 void TaskManagerPrerenderResourceProvider::StartUpdating() {
    481   DCHECK(!updating_);
    482   updating_ = true;
    483 
    484   // Add all the existing PrerenderContents.
    485   const ResourceDispatcherHost* resource_dispatcher_host =
    486       g_browser_process->resource_dispatcher_host();
    487   const ResourceDispatcherHost::PrerenderChildRouteIdPairs&
    488       prerender_child_route_id_pairs =
    489           resource_dispatcher_host->prerender_child_route_id_pairs();
    490   for (ResourceDispatcherHost::PrerenderChildRouteIdPairs::const_iterator it =
    491            prerender_child_route_id_pairs.begin();
    492        it != prerender_child_route_id_pairs.end();
    493        ++it) {
    494     Add(*it);
    495   }
    496 
    497   // Then we register for notifications to get new prerender items.
    498   registrar_.Add(this, NotificationType::PRERENDER_CONTENTS_STARTED,
    499                  NotificationService::AllSources());
    500   registrar_.Add(this, NotificationType::PRERENDER_CONTENTS_USED,
    501                  NotificationService::AllSources());
    502   registrar_.Add(this, NotificationType::PRERENDER_CONTENTS_DESTROYED,
    503                  NotificationService::AllSources());
    504 }
    505 
    506 void TaskManagerPrerenderResourceProvider::StopUpdating() {
    507   DCHECK(updating_);
    508   updating_ = false;
    509 
    510   // Then we unregister for notifications to get new prerender items.
    511   registrar_.Remove(this, NotificationType::PRERENDER_CONTENTS_STARTED,
    512                     NotificationService::AllSources());
    513   registrar_.Remove(this, NotificationType::PRERENDER_CONTENTS_USED,
    514                     NotificationService::AllSources());
    515   registrar_.Remove(this, NotificationType::PRERENDER_CONTENTS_DESTROYED,
    516                     NotificationService::AllSources());
    517 
    518   // Delete all the resources.
    519   STLDeleteContainerPairSecondPointers(resources_.begin(), resources_.end());
    520 
    521   resources_.clear();
    522 }
    523 
    524 void TaskManagerPrerenderResourceProvider::AddToTaskManager(
    525     const std::pair<int, int>& process_route_id_pair) {
    526   RenderViewHost* render_view_host =
    527       RenderViewHost::FromID(process_route_id_pair.first,
    528                              process_route_id_pair.second);
    529   CHECK(render_view_host);
    530   TaskManagerPrerenderResource* resource =
    531       new TaskManagerPrerenderResource(render_view_host);
    532   resources_[process_route_id_pair] = resource;
    533   task_manager_->AddResource(resource);
    534 }
    535 
    536 void TaskManagerPrerenderResourceProvider::Add(
    537     const std::pair<int, int>& process_route_id_pair) {
    538   if (!updating_)
    539     return;
    540 
    541   // Don't add dead prerender contents or prerender contents that haven't yet
    542   // started.
    543   RenderViewHost* render_view_host =
    544       RenderViewHost::FromID(process_route_id_pair.first,
    545                              process_route_id_pair.second);
    546   if (!render_view_host)
    547     return;
    548 
    549   AddToTaskManager(process_route_id_pair);
    550 }
    551 
    552 void TaskManagerPrerenderResourceProvider::Remove(
    553     const std::pair<int, int>& process_route_id_pair) {
    554   if (!updating_)
    555     return;
    556 
    557   RenderViewHost* render_view_host =
    558       RenderViewHost::FromID(process_route_id_pair.first,
    559                              process_route_id_pair.second);
    560 
    561   if (!render_view_host) {
    562     // This will happen if the PrerenderContents was used. We should have had a
    563     // PRERENDER_CONTENTS_USED message about it and already removed it, but
    564     // either way we can't remove a NULL resource.
    565     return;
    566   }
    567 
    568   ResourceMap::iterator iter = resources_.find(process_route_id_pair);
    569   DCHECK(iter != resources_.end());
    570 
    571   // Remove the resource from the Task Manager.
    572   TaskManagerPrerenderResource* resource = iter->second;
    573   task_manager_->RemoveResource(resource);
    574   // And from the provider.
    575   resources_.erase(iter);
    576   // Finally, delete the resource.
    577   delete resource;
    578 }
    579 
    580 void TaskManagerPrerenderResourceProvider::Observe(
    581     NotificationType type,
    582     const NotificationSource& source,
    583     const NotificationDetails& details) {
    584   DCHECK(NotificationService::NoDetails() == details);
    585   switch (type.value) {
    586     case NotificationType::PRERENDER_CONTENTS_STARTED:
    587       Add(*Source<std::pair<int, int> >(source).ptr());
    588       break;
    589     case NotificationType::PRERENDER_CONTENTS_USED:
    590     case NotificationType::PRERENDER_CONTENTS_DESTROYED:
    591       Remove(*Source<std::pair<int, int> >(source).ptr());
    592       break;
    593     default:
    594       NOTREACHED() << "Unexpected notification.";
    595       return;
    596   }
    597 }
    598 ////////////////////////////////////////////////////////////////////////////////
    599 // TaskManagerBackgroundContentsResource class
    600 ////////////////////////////////////////////////////////////////////////////////
    601 
    602 SkBitmap* TaskManagerBackgroundContentsResource::default_icon_ = NULL;
    603 
    604 TaskManagerBackgroundContentsResource::TaskManagerBackgroundContentsResource(
    605     BackgroundContents* background_contents,
    606     const string16& application_name)
    607     : TaskManagerRendererResource(
    608           background_contents->render_view_host()->process()->GetHandle(),
    609           background_contents->render_view_host()),
    610       background_contents_(background_contents),
    611       application_name_(application_name) {
    612   // Just use the same icon that other extension resources do.
    613   // TODO(atwilson): Use the favicon when that's available.
    614   if (!default_icon_) {
    615     ResourceBundle& rb = ResourceBundle::GetSharedInstance();
    616     default_icon_ = rb.GetBitmapNamed(IDR_PLUGIN);
    617   }
    618   // Ensure that the string has the appropriate direction markers (see comment
    619   // in TaskManagerTabContentsResource::GetTitle()).
    620   base::i18n::AdjustStringForLocaleDirection(&application_name_);
    621 }
    622 
    623 TaskManagerBackgroundContentsResource::~TaskManagerBackgroundContentsResource(
    624     ) {
    625 }
    626 
    627 string16 TaskManagerBackgroundContentsResource::GetTitle() const {
    628   string16 title = application_name_;
    629 
    630   if (title.empty()) {
    631     // No title (can't locate the parent app for some reason) so just display
    632     // the URL (properly forced to be LTR).
    633     title = base::i18n::GetDisplayStringInLTRDirectionality(
    634         UTF8ToUTF16(background_contents_->GetURL().spec()));
    635   }
    636   return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_BACKGROUND_PREFIX, title);
    637 }
    638 
    639 
    640 SkBitmap TaskManagerBackgroundContentsResource::GetIcon() const {
    641   return *default_icon_;
    642 }
    643 
    644 bool TaskManagerBackgroundContentsResource::IsBackground() const {
    645   return true;
    646 }
    647 
    648 ////////////////////////////////////////////////////////////////////////////////
    649 // TaskManagerBackgroundContentsResourceProvider class
    650 ////////////////////////////////////////////////////////////////////////////////
    651 
    652 TaskManagerBackgroundContentsResourceProvider::
    653     TaskManagerBackgroundContentsResourceProvider(TaskManager* task_manager)
    654     : updating_(false),
    655       task_manager_(task_manager) {
    656 }
    657 
    658 TaskManagerBackgroundContentsResourceProvider::
    659     ~TaskManagerBackgroundContentsResourceProvider() {
    660 }
    661 
    662 TaskManager::Resource*
    663 TaskManagerBackgroundContentsResourceProvider::GetResource(
    664     int origin_pid,
    665     int render_process_host_id,
    666     int routing_id) {
    667   BackgroundContents* contents = BackgroundContents::GetBackgroundContentsByID(
    668       render_process_host_id, routing_id);
    669   if (!contents)  // This resource no longer exists.
    670     return NULL;
    671 
    672   // If an origin PID was specified, the request is from a plugin, not the
    673   // render view host process
    674   if (origin_pid)
    675     return NULL;
    676 
    677   std::map<BackgroundContents*,
    678       TaskManagerBackgroundContentsResource*>::iterator res_iter =
    679       resources_.find(contents);
    680   if (res_iter == resources_.end())
    681     // Can happen if the page went away while a network request was being
    682     // performed.
    683     return NULL;
    684 
    685   return res_iter->second;
    686 }
    687 
    688 void TaskManagerBackgroundContentsResourceProvider::StartUpdating() {
    689   DCHECK(!updating_);
    690   updating_ = true;
    691 
    692   // Add all the existing BackgroundContents from every profile.
    693   ProfileManager* profile_manager = g_browser_process->profile_manager();
    694   std::vector<Profile*> profiles(profile_manager->GetLoadedProfiles());
    695   for (size_t i = 0; i < profiles.size(); ++i) {
    696     BackgroundContentsService* background_contents_service =
    697         BackgroundContentsServiceFactory::GetForProfile(profiles[i]);
    698     ExtensionService* extensions_service = profiles[i]->GetExtensionService();
    699     std::vector<BackgroundContents*> contents =
    700         background_contents_service->GetBackgroundContents();
    701     for (std::vector<BackgroundContents*>::iterator iterator = contents.begin();
    702          iterator != contents.end(); ++iterator) {
    703       string16 application_name;
    704       // Lookup the name from the parent extension.
    705       if (extensions_service) {
    706         const string16& application_id =
    707             background_contents_service->GetParentApplicationId(*iterator);
    708         const Extension* extension = extensions_service->GetExtensionById(
    709             UTF16ToUTF8(application_id), false);
    710         if (extension)
    711           application_name = UTF8ToUTF16(extension->name());
    712       }
    713       Add(*iterator, application_name);
    714     }
    715   }
    716 
    717   // Then we register for notifications to get new BackgroundContents.
    718   registrar_.Add(this, NotificationType::BACKGROUND_CONTENTS_OPENED,
    719                  NotificationService::AllSources());
    720   registrar_.Add(this, NotificationType::BACKGROUND_CONTENTS_NAVIGATED,
    721                  NotificationService::AllSources());
    722   registrar_.Add(this, NotificationType::BACKGROUND_CONTENTS_DELETED,
    723                  NotificationService::AllSources());
    724 }
    725 
    726 void TaskManagerBackgroundContentsResourceProvider::StopUpdating() {
    727   DCHECK(updating_);
    728   updating_ = false;
    729 
    730   // Unregister for notifications
    731   registrar_.Remove(this, NotificationType::BACKGROUND_CONTENTS_OPENED,
    732                     NotificationService::AllSources());
    733   registrar_.Remove(this, NotificationType::BACKGROUND_CONTENTS_NAVIGATED,
    734                     NotificationService::AllSources());
    735   registrar_.Remove(this, NotificationType::BACKGROUND_CONTENTS_DELETED,
    736                     NotificationService::AllSources());
    737 
    738   // Delete all the resources.
    739   STLDeleteContainerPairSecondPointers(resources_.begin(), resources_.end());
    740 
    741   resources_.clear();
    742 }
    743 
    744 void TaskManagerBackgroundContentsResourceProvider::AddToTaskManager(
    745     BackgroundContents* background_contents,
    746     const string16& application_name) {
    747   TaskManagerBackgroundContentsResource* resource =
    748       new TaskManagerBackgroundContentsResource(background_contents,
    749                                                 application_name);
    750   resources_[background_contents] = resource;
    751   task_manager_->AddResource(resource);
    752 }
    753 
    754 void TaskManagerBackgroundContentsResourceProvider::Add(
    755     BackgroundContents* contents, const string16& application_name) {
    756   if (!updating_)
    757     return;
    758 
    759   // Don't add contents whose process is dead.
    760   if (!contents->render_view_host()->process()->GetHandle())
    761     return;
    762 
    763   // Should never add the same BackgroundContents twice.
    764   DCHECK(resources_.find(contents) == resources_.end());
    765   AddToTaskManager(contents, application_name);
    766 }
    767 
    768 void TaskManagerBackgroundContentsResourceProvider::Remove(
    769     BackgroundContents* contents) {
    770   if (!updating_)
    771     return;
    772   std::map<BackgroundContents*,
    773       TaskManagerBackgroundContentsResource*>::iterator iter =
    774       resources_.find(contents);
    775   DCHECK(iter != resources_.end());
    776 
    777   // Remove the resource from the Task Manager.
    778   TaskManagerBackgroundContentsResource* resource = iter->second;
    779   task_manager_->RemoveResource(resource);
    780   // And from the provider.
    781   resources_.erase(iter);
    782   // Finally, delete the resource.
    783   delete resource;
    784 }
    785 
    786 void TaskManagerBackgroundContentsResourceProvider::Observe(
    787     NotificationType type,
    788     const NotificationSource& source,
    789     const NotificationDetails& details) {
    790   switch (type.value) {
    791     case NotificationType::BACKGROUND_CONTENTS_OPENED: {
    792       // Get the name from the parent application. If no parent application is
    793       // found, just pass an empty string - BackgroundContentsResource::GetTitle
    794       // will display the URL instead in this case. This should never happen
    795       // except in rare cases when an extension is being unloaded or chrome is
    796       // exiting while the task manager is displayed.
    797       string16 application_name;
    798       ExtensionService* service =
    799           Source<Profile>(source)->GetExtensionService();
    800       if (service) {
    801         std::string application_id = UTF16ToUTF8(
    802             Details<BackgroundContentsOpenedDetails>(details)->application_id);
    803         const Extension* extension =
    804             service->GetExtensionById(application_id, false);
    805         // Extension can be NULL when running unit tests.
    806         if (extension)
    807           application_name = UTF8ToUTF16(extension->name());
    808       }
    809       Add(Details<BackgroundContentsOpenedDetails>(details)->contents,
    810           application_name);
    811       // Opening a new BackgroundContents needs to force the display to refresh
    812       // (applications may now be considered "background" that weren't before).
    813       task_manager_->ModelChanged();
    814       break;
    815     }
    816     case NotificationType::BACKGROUND_CONTENTS_NAVIGATED: {
    817       BackgroundContents* contents = Details<BackgroundContents>(details).ptr();
    818       // Should never get a NAVIGATED before OPENED.
    819       DCHECK(resources_.find(contents) != resources_.end());
    820       // Preserve the application name.
    821       string16 application_name(
    822           resources_.find(contents)->second->application_name());
    823       Remove(contents);
    824       Add(contents, application_name);
    825       break;
    826     }
    827     case NotificationType::BACKGROUND_CONTENTS_DELETED:
    828       Remove(Details<BackgroundContents>(details).ptr());
    829       // Closing a BackgroundContents needs to force the display to refresh
    830       // (applications may now be considered "foreground" that weren't before).
    831       task_manager_->ModelChanged();
    832       break;
    833     default:
    834       NOTREACHED() << "Unexpected notification.";
    835       return;
    836   }
    837 }
    838 
    839 ////////////////////////////////////////////////////////////////////////////////
    840 // TaskManagerChildProcessResource class
    841 ////////////////////////////////////////////////////////////////////////////////
    842 SkBitmap* TaskManagerChildProcessResource::default_icon_ = NULL;
    843 
    844 TaskManagerChildProcessResource::TaskManagerChildProcessResource(
    845     const ChildProcessInfo& child_proc)
    846     : child_process_(child_proc),
    847       title_(),
    848       network_usage_support_(false) {
    849   // We cache the process id because it's not cheap to calculate, and it won't
    850   // be available when we get the plugin disconnected notification.
    851   pid_ = child_proc.pid();
    852   if (!default_icon_) {
    853     ResourceBundle& rb = ResourceBundle::GetSharedInstance();
    854     default_icon_ = rb.GetBitmapNamed(IDR_PLUGIN);
    855     // TODO(jabdelmalek): use different icon for web workers.
    856   }
    857 }
    858 
    859 TaskManagerChildProcessResource::~TaskManagerChildProcessResource() {
    860 }
    861 
    862 // TaskManagerResource methods:
    863 string16 TaskManagerChildProcessResource::GetTitle() const {
    864   if (title_.empty())
    865     title_ = GetLocalizedTitle();
    866 
    867   return title_;
    868 }
    869 
    870 SkBitmap TaskManagerChildProcessResource::GetIcon() const {
    871   return *default_icon_;
    872 }
    873 
    874 base::ProcessHandle TaskManagerChildProcessResource::GetProcess() const {
    875   return child_process_.handle();
    876 }
    877 
    878 TaskManager::Resource::Type TaskManagerChildProcessResource::GetType() const {
    879   // Translate types to TaskManager::ResourceType, since ChildProcessInfo's type
    880   // is not available for all TaskManager resources.
    881   switch (child_process_.type()) {
    882     case ChildProcessInfo::BROWSER_PROCESS:
    883       return TaskManager::Resource::BROWSER;
    884     case ChildProcessInfo::RENDER_PROCESS:
    885       return TaskManager::Resource::RENDERER;
    886     case ChildProcessInfo::PLUGIN_PROCESS:
    887       return TaskManager::Resource::PLUGIN;
    888     case ChildProcessInfo::WORKER_PROCESS:
    889       return TaskManager::Resource::WORKER;
    890     case ChildProcessInfo::NACL_LOADER_PROCESS:
    891     case ChildProcessInfo::NACL_BROKER_PROCESS:
    892       return TaskManager::Resource::NACL;
    893     case ChildProcessInfo::UTILITY_PROCESS:
    894       return TaskManager::Resource::UTILITY;
    895     case ChildProcessInfo::PROFILE_IMPORT_PROCESS:
    896       return TaskManager::Resource::PROFILE_IMPORT;
    897     case ChildProcessInfo::ZYGOTE_PROCESS:
    898       return TaskManager::Resource::ZYGOTE;
    899     case ChildProcessInfo::SANDBOX_HELPER_PROCESS:
    900       return TaskManager::Resource::SANDBOX_HELPER;
    901     case ChildProcessInfo::GPU_PROCESS:
    902       return TaskManager::Resource::GPU;
    903     default:
    904       return TaskManager::Resource::UNKNOWN;
    905   }
    906 }
    907 
    908 bool TaskManagerChildProcessResource::SupportNetworkUsage() const {
    909   return network_usage_support_;
    910 }
    911 
    912 void TaskManagerChildProcessResource::SetSupportNetworkUsage() {
    913   network_usage_support_ = true;
    914 }
    915 
    916 string16 TaskManagerChildProcessResource::GetLocalizedTitle() const {
    917   string16 title = WideToUTF16Hack(child_process_.name());
    918   if (child_process_.type() == ChildProcessInfo::PLUGIN_PROCESS &&
    919       title.empty()) {
    920     title = l10n_util::GetStringUTF16(IDS_TASK_MANAGER_UNKNOWN_PLUGIN_NAME);
    921   }
    922 
    923   // Explicitly mark name as LTR if there is no strong RTL character,
    924   // to avoid the wrong concatenation result similar to "!Yahoo! Mail: the
    925   // best web-based Email: NIGULP", in which "NIGULP" stands for the Hebrew
    926   // or Arabic word for "plugin".
    927   base::i18n::AdjustStringForLocaleDirection(&title);
    928 
    929   switch (child_process_.type()) {
    930     case ChildProcessInfo::UTILITY_PROCESS:
    931       return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_UTILITY_PREFIX);
    932 
    933     case ChildProcessInfo::PROFILE_IMPORT_PROCESS:
    934       return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_UTILITY_PREFIX);
    935 
    936     case ChildProcessInfo::GPU_PROCESS:
    937       return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_GPU_PREFIX);
    938 
    939     case ChildProcessInfo::NACL_BROKER_PROCESS:
    940       return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NACL_BROKER_PREFIX);
    941 
    942     case ChildProcessInfo::PLUGIN_PROCESS:
    943     case ChildProcessInfo::PPAPI_PLUGIN_PROCESS:
    944     case ChildProcessInfo::PPAPI_BROKER_PROCESS: {
    945       return l10n_util::GetStringFUTF16(
    946           IDS_TASK_MANAGER_PLUGIN_PREFIX, title,
    947           WideToUTF16Hack(child_process_.version()));
    948     }
    949 
    950     case ChildProcessInfo::NACL_LOADER_PROCESS:
    951       return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_NACL_PREFIX, title);
    952 
    953     case ChildProcessInfo::WORKER_PROCESS:
    954       return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_WORKER_PREFIX, title);
    955 
    956     // These types don't need display names or get them from elsewhere.
    957     case ChildProcessInfo::BROWSER_PROCESS:
    958     case ChildProcessInfo::RENDER_PROCESS:
    959     case ChildProcessInfo::ZYGOTE_PROCESS:
    960     case ChildProcessInfo::SANDBOX_HELPER_PROCESS:
    961       NOTREACHED();
    962       break;
    963 
    964     case ChildProcessInfo::UNKNOWN_PROCESS:
    965       NOTREACHED() << "Need localized name for child process type.";
    966   }
    967 
    968   return title;
    969 }
    970 
    971 ////////////////////////////////////////////////////////////////////////////////
    972 // TaskManagerChildProcessResourceProvider class
    973 ////////////////////////////////////////////////////////////////////////////////
    974 
    975 TaskManagerChildProcessResourceProvider::
    976     TaskManagerChildProcessResourceProvider(TaskManager* task_manager)
    977     : updating_(false),
    978       task_manager_(task_manager) {
    979 }
    980 
    981 TaskManagerChildProcessResourceProvider::
    982     ~TaskManagerChildProcessResourceProvider() {
    983 }
    984 
    985 TaskManager::Resource* TaskManagerChildProcessResourceProvider::GetResource(
    986     int origin_pid,
    987     int render_process_host_id,
    988     int routing_id) {
    989   std::map<int, TaskManagerChildProcessResource*>::iterator iter =
    990       pid_to_resources_.find(origin_pid);
    991   if (iter != pid_to_resources_.end())
    992     return iter->second;
    993   else
    994     return NULL;
    995 }
    996 
    997 void TaskManagerChildProcessResourceProvider::StartUpdating() {
    998   DCHECK(!updating_);
    999   updating_ = true;
   1000 
   1001   // Register for notifications to get new child processes.
   1002   registrar_.Add(this, NotificationType::CHILD_PROCESS_HOST_CONNECTED,
   1003                  NotificationService::AllSources());
   1004   registrar_.Add(this, NotificationType::CHILD_PROCESS_HOST_DISCONNECTED,
   1005                  NotificationService::AllSources());
   1006 
   1007   // Get the existing child processes.
   1008   BrowserThread::PostTask(
   1009       BrowserThread::IO, FROM_HERE,
   1010       NewRunnableMethod(
   1011           this,
   1012           &TaskManagerChildProcessResourceProvider::RetrieveChildProcessInfo));
   1013 }
   1014 
   1015 void TaskManagerChildProcessResourceProvider::StopUpdating() {
   1016   DCHECK(updating_);
   1017   updating_ = false;
   1018 
   1019   // Unregister for notifications to get new plugin processes.
   1020   registrar_.Remove(this, NotificationType::CHILD_PROCESS_HOST_CONNECTED,
   1021                     NotificationService::AllSources());
   1022   registrar_.Remove(this,
   1023                     NotificationType::CHILD_PROCESS_HOST_DISCONNECTED,
   1024                     NotificationService::AllSources());
   1025 
   1026   // Delete all the resources.
   1027   STLDeleteContainerPairSecondPointers(resources_.begin(), resources_.end());
   1028 
   1029   resources_.clear();
   1030   pid_to_resources_.clear();
   1031   existing_child_process_info_.clear();
   1032 }
   1033 
   1034 void TaskManagerChildProcessResourceProvider::Observe(
   1035     NotificationType type,
   1036     const NotificationSource& source,
   1037     const NotificationDetails& details) {
   1038   switch (type.value) {
   1039     case NotificationType::CHILD_PROCESS_HOST_CONNECTED:
   1040       Add(*Details<ChildProcessInfo>(details).ptr());
   1041       break;
   1042     case NotificationType::CHILD_PROCESS_HOST_DISCONNECTED:
   1043       Remove(*Details<ChildProcessInfo>(details).ptr());
   1044       break;
   1045     default:
   1046       NOTREACHED() << "Unexpected notification.";
   1047       return;
   1048   }
   1049 }
   1050 
   1051 void TaskManagerChildProcessResourceProvider::Add(
   1052     const ChildProcessInfo& child_process_info) {
   1053   if (!updating_)
   1054     return;
   1055   std::map<ChildProcessInfo, TaskManagerChildProcessResource*>::
   1056       const_iterator iter = resources_.find(child_process_info);
   1057   if (iter != resources_.end()) {
   1058     // The case may happen that we have added a child_process_info as part of
   1059     // the iteration performed during StartUpdating() call but the notification
   1060     // that it has connected was not fired yet. So when the notification
   1061     // happens, we already know about this plugin and just ignore it.
   1062     return;
   1063   }
   1064   AddToTaskManager(child_process_info);
   1065 }
   1066 
   1067 void TaskManagerChildProcessResourceProvider::Remove(
   1068     const ChildProcessInfo& child_process_info) {
   1069   if (!updating_)
   1070     return;
   1071   std::map<ChildProcessInfo, TaskManagerChildProcessResource*>
   1072       ::iterator iter = resources_.find(child_process_info);
   1073   if (iter == resources_.end()) {
   1074     // ChildProcessInfo disconnection notifications are asynchronous, so we
   1075     // might be notified for a plugin we don't know anything about (if it was
   1076     // closed before the task manager was shown and destroyed after that).
   1077     return;
   1078   }
   1079   // Remove the resource from the Task Manager.
   1080   TaskManagerChildProcessResource* resource = iter->second;
   1081   task_manager_->RemoveResource(resource);
   1082   // Remove it from the provider.
   1083   resources_.erase(iter);
   1084   // Remove it from our pid map.
   1085   std::map<int, TaskManagerChildProcessResource*>::iterator pid_iter =
   1086       pid_to_resources_.find(resource->process_id());
   1087   DCHECK(pid_iter != pid_to_resources_.end());
   1088   if (pid_iter != pid_to_resources_.end())
   1089     pid_to_resources_.erase(pid_iter);
   1090 
   1091   // Finally, delete the resource.
   1092   delete resource;
   1093 }
   1094 
   1095 void TaskManagerChildProcessResourceProvider::AddToTaskManager(
   1096     const ChildProcessInfo& child_process_info) {
   1097   TaskManagerChildProcessResource* resource =
   1098       new TaskManagerChildProcessResource(child_process_info);
   1099   resources_[child_process_info] = resource;
   1100   pid_to_resources_[resource->process_id()] = resource;
   1101   task_manager_->AddResource(resource);
   1102 }
   1103 
   1104 // The ChildProcessInfo::Iterator has to be used from the IO thread.
   1105 void TaskManagerChildProcessResourceProvider::RetrieveChildProcessInfo() {
   1106   for (BrowserChildProcessHost::Iterator iter; !iter.Done(); ++iter) {
   1107     // Only add processes which are already started, since we need their handle.
   1108     if ((*iter)->handle() != base::kNullProcessHandle)
   1109       existing_child_process_info_.push_back(**iter);
   1110   }
   1111   // Now notify the UI thread that we have retrieved information about child
   1112   // processes.
   1113   BrowserThread::PostTask(
   1114       BrowserThread::UI, FROM_HERE,
   1115       NewRunnableMethod(this,
   1116           &TaskManagerChildProcessResourceProvider::ChildProcessInfoRetreived));
   1117 }
   1118 
   1119 // This is called on the UI thread.
   1120 void TaskManagerChildProcessResourceProvider::ChildProcessInfoRetreived() {
   1121   std::vector<ChildProcessInfo>::const_iterator iter;
   1122   for (iter = existing_child_process_info_.begin();
   1123        iter != existing_child_process_info_.end(); ++iter) {
   1124     Add(*iter);
   1125   }
   1126   existing_child_process_info_.clear();
   1127 }
   1128 
   1129 ////////////////////////////////////////////////////////////////////////////////
   1130 // TaskManagerExtensionProcessResource class
   1131 ////////////////////////////////////////////////////////////////////////////////
   1132 
   1133 SkBitmap* TaskManagerExtensionProcessResource::default_icon_ = NULL;
   1134 
   1135 TaskManagerExtensionProcessResource::TaskManagerExtensionProcessResource(
   1136     ExtensionHost* extension_host)
   1137     : extension_host_(extension_host) {
   1138   if (!default_icon_) {
   1139     ResourceBundle& rb = ResourceBundle::GetSharedInstance();
   1140     default_icon_ = rb.GetBitmapNamed(IDR_PLUGIN);
   1141   }
   1142   process_handle_ = extension_host_->render_process_host()->GetHandle();
   1143   pid_ = base::GetProcId(process_handle_);
   1144   string16 extension_name = UTF8ToUTF16(GetExtension()->name());
   1145   DCHECK(!extension_name.empty());
   1146 
   1147   int message_id = GetMessagePrefixID(GetExtension()->is_app(), true,
   1148       extension_host_->profile()->IsOffTheRecord());
   1149   title_ = l10n_util::GetStringFUTF16(message_id, extension_name);
   1150 }
   1151 
   1152 TaskManagerExtensionProcessResource::~TaskManagerExtensionProcessResource() {
   1153 }
   1154 
   1155 string16 TaskManagerExtensionProcessResource::GetTitle() const {
   1156   return title_;
   1157 }
   1158 
   1159 SkBitmap TaskManagerExtensionProcessResource::GetIcon() const {
   1160   return *default_icon_;
   1161 }
   1162 
   1163 base::ProcessHandle TaskManagerExtensionProcessResource::GetProcess() const {
   1164   return process_handle_;
   1165 }
   1166 
   1167 TaskManager::Resource::Type
   1168 TaskManagerExtensionProcessResource::GetType() const {
   1169   return EXTENSION;
   1170 }
   1171 
   1172 bool TaskManagerExtensionProcessResource::SupportNetworkUsage() const {
   1173   return true;
   1174 }
   1175 
   1176 void TaskManagerExtensionProcessResource::SetSupportNetworkUsage() {
   1177   NOTREACHED();
   1178 }
   1179 
   1180 const Extension* TaskManagerExtensionProcessResource::GetExtension() const {
   1181   return extension_host_->extension();
   1182 }
   1183 
   1184 bool TaskManagerExtensionProcessResource::IsBackground() const {
   1185   return extension_host_->GetRenderViewType() ==
   1186       ViewType::EXTENSION_BACKGROUND_PAGE;
   1187 }
   1188 
   1189 ////////////////////////////////////////////////////////////////////////////////
   1190 // TaskManagerExtensionProcessResourceProvider class
   1191 ////////////////////////////////////////////////////////////////////////////////
   1192 
   1193 TaskManagerExtensionProcessResourceProvider::
   1194     TaskManagerExtensionProcessResourceProvider(TaskManager* task_manager)
   1195     : task_manager_(task_manager),
   1196       updating_(false) {
   1197 }
   1198 
   1199 TaskManagerExtensionProcessResourceProvider::
   1200     ~TaskManagerExtensionProcessResourceProvider() {
   1201 }
   1202 
   1203 TaskManager::Resource* TaskManagerExtensionProcessResourceProvider::GetResource(
   1204     int origin_pid,
   1205     int render_process_host_id,
   1206     int routing_id) {
   1207   std::map<int, TaskManagerExtensionProcessResource*>::iterator iter =
   1208       pid_to_resources_.find(origin_pid);
   1209   if (iter != pid_to_resources_.end())
   1210     return iter->second;
   1211   else
   1212     return NULL;
   1213 }
   1214 
   1215 void TaskManagerExtensionProcessResourceProvider::StartUpdating() {
   1216   DCHECK(!updating_);
   1217   updating_ = true;
   1218 
   1219   // Add all the existing ExtensionHosts.
   1220   ProfileManager* profile_manager = g_browser_process->profile_manager();
   1221   std::vector<Profile*> profiles(profile_manager->GetLoadedProfiles());
   1222   for (size_t i = 0; i < profiles.size(); ++i) {
   1223     ExtensionProcessManager* process_manager =
   1224         profiles[i]->GetExtensionProcessManager();
   1225     if (process_manager) {
   1226       ExtensionProcessManager::const_iterator jt;
   1227       for (jt = process_manager->begin(); jt != process_manager->end(); ++jt)
   1228         AddToTaskManager(*jt);
   1229     }
   1230 
   1231     // If we have an incognito profile active, include the split-mode incognito
   1232     // extensions.
   1233     if (BrowserList::IsOffTheRecordSessionActive()) {
   1234       ExtensionProcessManager* process_manager =
   1235           profiles[i]->GetOffTheRecordProfile()->GetExtensionProcessManager();
   1236       if (process_manager) {
   1237       ExtensionProcessManager::const_iterator jt;
   1238       for (jt = process_manager->begin(); jt != process_manager->end(); ++jt)
   1239         AddToTaskManager(*jt);
   1240       }
   1241     }
   1242   }
   1243 
   1244   // Register for notifications about extension process changes.
   1245   registrar_.Add(this, NotificationType::EXTENSION_PROCESS_CREATED,
   1246                  NotificationService::AllSources());
   1247   registrar_.Add(this, NotificationType::EXTENSION_PROCESS_TERMINATED,
   1248                  NotificationService::AllSources());
   1249   registrar_.Add(this, NotificationType::EXTENSION_HOST_DESTROYED,
   1250                  NotificationService::AllSources());
   1251 }
   1252 
   1253 void TaskManagerExtensionProcessResourceProvider::StopUpdating() {
   1254   DCHECK(updating_);
   1255   updating_ = false;
   1256 
   1257   // Unregister for notifications about extension process changes.
   1258   registrar_.Remove(this, NotificationType::EXTENSION_PROCESS_CREATED,
   1259                     NotificationService::AllSources());
   1260   registrar_.Remove(this, NotificationType::EXTENSION_PROCESS_TERMINATED,
   1261                     NotificationService::AllSources());
   1262   registrar_.Remove(this, NotificationType::EXTENSION_HOST_DESTROYED,
   1263                     NotificationService::AllSources());
   1264 
   1265   // Delete all the resources.
   1266   STLDeleteContainerPairSecondPointers(resources_.begin(), resources_.end());
   1267 
   1268   resources_.clear();
   1269   pid_to_resources_.clear();
   1270 }
   1271 
   1272 void TaskManagerExtensionProcessResourceProvider::Observe(
   1273     NotificationType type,
   1274     const NotificationSource& source,
   1275     const NotificationDetails& details) {
   1276   switch (type.value) {
   1277     case NotificationType::EXTENSION_PROCESS_CREATED:
   1278       AddToTaskManager(Details<ExtensionHost>(details).ptr());
   1279       break;
   1280     case NotificationType::EXTENSION_PROCESS_TERMINATED:
   1281     case NotificationType::EXTENSION_HOST_DESTROYED:
   1282       RemoveFromTaskManager(Details<ExtensionHost>(details).ptr());
   1283       break;
   1284     default:
   1285       NOTREACHED() << "Unexpected notification.";
   1286       return;
   1287   }
   1288 }
   1289 
   1290 void TaskManagerExtensionProcessResourceProvider::AddToTaskManager(
   1291     ExtensionHost* extension_host) {
   1292   // Don't add dead extension processes.
   1293   if (!extension_host->IsRenderViewLive())
   1294     return;
   1295 
   1296   TaskManagerExtensionProcessResource* resource =
   1297       new TaskManagerExtensionProcessResource(extension_host);
   1298   DCHECK(resources_.find(extension_host) == resources_.end());
   1299   resources_[extension_host] = resource;
   1300   pid_to_resources_[resource->process_id()] = resource;
   1301   task_manager_->AddResource(resource);
   1302 }
   1303 
   1304 void TaskManagerExtensionProcessResourceProvider::RemoveFromTaskManager(
   1305     ExtensionHost* extension_host) {
   1306   if (!updating_)
   1307     return;
   1308   std::map<ExtensionHost*, TaskManagerExtensionProcessResource*>
   1309       ::iterator iter = resources_.find(extension_host);
   1310   if (iter == resources_.end())
   1311     return;
   1312 
   1313   // Remove the resource from the Task Manager.
   1314   TaskManagerExtensionProcessResource* resource = iter->second;
   1315   task_manager_->RemoveResource(resource);
   1316 
   1317   // Remove it from the provider.
   1318   resources_.erase(iter);
   1319 
   1320   // Remove it from our pid map.
   1321   std::map<int, TaskManagerExtensionProcessResource*>::iterator pid_iter =
   1322       pid_to_resources_.find(resource->process_id());
   1323   DCHECK(pid_iter != pid_to_resources_.end());
   1324   if (pid_iter != pid_to_resources_.end())
   1325     pid_to_resources_.erase(pid_iter);
   1326 
   1327   // Finally, delete the resource.
   1328   delete resource;
   1329 }
   1330 
   1331 ////////////////////////////////////////////////////////////////////////////////
   1332 // TaskManagerNotificationResource class
   1333 ////////////////////////////////////////////////////////////////////////////////
   1334 
   1335 SkBitmap* TaskManagerNotificationResource::default_icon_ = NULL;
   1336 
   1337 TaskManagerNotificationResource::TaskManagerNotificationResource(
   1338     BalloonHost* balloon_host)
   1339     : balloon_host_(balloon_host) {
   1340   if (!default_icon_) {
   1341     ResourceBundle& rb = ResourceBundle::GetSharedInstance();
   1342     default_icon_ = rb.GetBitmapNamed(IDR_PLUGIN);
   1343   }
   1344   process_handle_ = balloon_host_->render_view_host()->process()->GetHandle();
   1345   pid_ = base::GetProcId(process_handle_);
   1346   title_ = l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_NOTIFICATION_PREFIX,
   1347                                       balloon_host_->GetSource());
   1348 }
   1349 
   1350 TaskManagerNotificationResource::~TaskManagerNotificationResource() {
   1351 }
   1352 
   1353 string16 TaskManagerNotificationResource::GetTitle() const {
   1354   return title_;
   1355 }
   1356 
   1357 SkBitmap TaskManagerNotificationResource::GetIcon() const {
   1358   return *default_icon_;
   1359 }
   1360 
   1361 base::ProcessHandle TaskManagerNotificationResource::GetProcess() const {
   1362   return process_handle_;
   1363 }
   1364 
   1365 TaskManager::Resource::Type TaskManagerNotificationResource::GetType() const {
   1366   return NOTIFICATION;
   1367 }
   1368 
   1369 bool TaskManagerNotificationResource::SupportNetworkUsage() const {
   1370   return false;
   1371 }
   1372 
   1373 ////////////////////////////////////////////////////////////////////////////////
   1374 // TaskManagerNotificationResourceProvider class
   1375 ////////////////////////////////////////////////////////////////////////////////
   1376 
   1377 TaskManagerNotificationResourceProvider::
   1378     TaskManagerNotificationResourceProvider(TaskManager* task_manager)
   1379     : task_manager_(task_manager),
   1380       updating_(false) {
   1381 }
   1382 
   1383 TaskManagerNotificationResourceProvider::
   1384     ~TaskManagerNotificationResourceProvider() {
   1385 }
   1386 
   1387 TaskManager::Resource* TaskManagerNotificationResourceProvider::GetResource(
   1388     int origin_pid,
   1389     int render_process_host_id,
   1390     int routing_id) {
   1391   // TODO(johnnyg): provide resources by pid if necessary.
   1392   return NULL;
   1393 }
   1394 
   1395 void TaskManagerNotificationResourceProvider::StartUpdating() {
   1396   DCHECK(!updating_);
   1397   updating_ = true;
   1398 
   1399   // Add all the existing BalloonHosts.
   1400   BalloonCollection* collection =
   1401       g_browser_process->notification_ui_manager()->balloon_collection();
   1402   const BalloonCollection::Balloons& balloons = collection->GetActiveBalloons();
   1403   for (BalloonCollection::Balloons::const_iterator it = balloons.begin();
   1404        it != balloons.end(); ++it) {
   1405     AddToTaskManager((*it)->view()->GetHost());
   1406   }
   1407 
   1408   // Register for notifications about extension process changes.
   1409   registrar_.Add(this, NotificationType::NOTIFY_BALLOON_CONNECTED,
   1410                  NotificationService::AllSources());
   1411   registrar_.Add(this, NotificationType::NOTIFY_BALLOON_DISCONNECTED,
   1412                  NotificationService::AllSources());
   1413 }
   1414 
   1415 void TaskManagerNotificationResourceProvider::StopUpdating() {
   1416   DCHECK(updating_);
   1417   updating_ = false;
   1418 
   1419   // Unregister for notifications about extension process changes.
   1420   registrar_.Remove(this, NotificationType::NOTIFY_BALLOON_CONNECTED,
   1421                     NotificationService::AllSources());
   1422   registrar_.Remove(this, NotificationType::NOTIFY_BALLOON_DISCONNECTED,
   1423                     NotificationService::AllSources());
   1424 
   1425   // Delete all the resources.
   1426   STLDeleteContainerPairSecondPointers(resources_.begin(), resources_.end());
   1427   resources_.clear();
   1428 }
   1429 
   1430 void TaskManagerNotificationResourceProvider::Observe(
   1431     NotificationType type,
   1432     const NotificationSource& source,
   1433     const NotificationDetails& details) {
   1434   switch (type.value) {
   1435     case NotificationType::NOTIFY_BALLOON_CONNECTED:
   1436       AddToTaskManager(Source<BalloonHost>(source).ptr());
   1437       break;
   1438     case NotificationType::NOTIFY_BALLOON_DISCONNECTED:
   1439       RemoveFromTaskManager(Source<BalloonHost>(source).ptr());
   1440       break;
   1441     default:
   1442       NOTREACHED() << "Unexpected notification.";
   1443       return;
   1444   }
   1445 }
   1446 
   1447 void TaskManagerNotificationResourceProvider::AddToTaskManager(
   1448     BalloonHost* balloon_host) {
   1449   TaskManagerNotificationResource* resource =
   1450       new TaskManagerNotificationResource(balloon_host);
   1451   DCHECK(resources_.find(balloon_host) == resources_.end());
   1452   resources_[balloon_host] = resource;
   1453   task_manager_->AddResource(resource);
   1454 }
   1455 
   1456 void TaskManagerNotificationResourceProvider::RemoveFromTaskManager(
   1457     BalloonHost* balloon_host) {
   1458   if (!updating_)
   1459     return;
   1460   std::map<BalloonHost*, TaskManagerNotificationResource*>::iterator iter =
   1461       resources_.find(balloon_host);
   1462   if (iter == resources_.end())
   1463     return;
   1464 
   1465   // Remove the resource from the Task Manager.
   1466   TaskManagerNotificationResource* resource = iter->second;
   1467   task_manager_->RemoveResource(resource);
   1468 
   1469   // Remove it from the map.
   1470   resources_.erase(iter);
   1471 
   1472   // Finally, delete the resource.
   1473   delete resource;
   1474 }
   1475 
   1476 ////////////////////////////////////////////////////////////////////////////////
   1477 // TaskManagerBrowserProcessResource class
   1478 ////////////////////////////////////////////////////////////////////////////////
   1479 
   1480 SkBitmap* TaskManagerBrowserProcessResource::default_icon_ = NULL;
   1481 
   1482 TaskManagerBrowserProcessResource::TaskManagerBrowserProcessResource()
   1483     : title_() {
   1484   int pid = base::GetCurrentProcId();
   1485   bool success = base::OpenPrivilegedProcessHandle(pid, &process_);
   1486   DCHECK(success);
   1487 #if defined(OS_WIN)
   1488   if (!default_icon_) {
   1489     HICON icon = GetAppIcon();
   1490     if (icon) {
   1491       ICONINFO icon_info = {0};
   1492       BITMAP bitmap_info = {0};
   1493 
   1494       GetIconInfo(icon, &icon_info);
   1495       GetObject(icon_info.hbmMask, sizeof(bitmap_info), &bitmap_info);
   1496 
   1497       gfx::Size icon_size(bitmap_info.bmWidth, bitmap_info.bmHeight);
   1498       default_icon_ = IconUtil::CreateSkBitmapFromHICON(icon, icon_size);
   1499     }
   1500   }
   1501 #elif defined(OS_LINUX)
   1502   if (!default_icon_) {
   1503     ResourceBundle& rb = ResourceBundle::GetSharedInstance();
   1504     default_icon_ = rb.GetBitmapNamed(IDR_PRODUCT_LOGO_16);
   1505   }
   1506 #elif defined(OS_MACOSX)
   1507   if (!default_icon_) {
   1508     // IDR_PRODUCT_LOGO_16 doesn't quite look like chrome/mac's icns icon. Load
   1509     // the real app icon (requires a nsimage->skbitmap->nsimage conversion :-().
   1510     default_icon_ = new SkBitmap(gfx::AppplicationIconAtSize(16));
   1511   }
   1512 #else
   1513   // TODO(port): Port icon code.
   1514   NOTIMPLEMENTED();
   1515 #endif  // defined(OS_WIN)
   1516 }
   1517 
   1518 TaskManagerBrowserProcessResource::~TaskManagerBrowserProcessResource() {
   1519   base::CloseProcessHandle(process_);
   1520 }
   1521 
   1522 // TaskManagerResource methods:
   1523 string16 TaskManagerBrowserProcessResource::GetTitle() const {
   1524   if (title_.empty()) {
   1525     title_ = l10n_util::GetStringUTF16(IDS_TASK_MANAGER_WEB_BROWSER_CELL_TEXT);
   1526   }
   1527   return title_;
   1528 }
   1529 
   1530 SkBitmap TaskManagerBrowserProcessResource::GetIcon() const {
   1531   return *default_icon_;
   1532 }
   1533 
   1534 size_t TaskManagerBrowserProcessResource::SqliteMemoryUsedBytes() const {
   1535   return static_cast<size_t>(sqlite3_memory_used());
   1536 }
   1537 
   1538 base::ProcessHandle TaskManagerBrowserProcessResource::GetProcess() const {
   1539   return base::GetCurrentProcessHandle();  // process_;
   1540 }
   1541 
   1542 TaskManager::Resource::Type TaskManagerBrowserProcessResource::GetType() const {
   1543   return BROWSER;
   1544 }
   1545 
   1546 bool TaskManagerBrowserProcessResource::SupportNetworkUsage() const {
   1547   return true;
   1548 }
   1549 
   1550 void TaskManagerBrowserProcessResource::SetSupportNetworkUsage() {
   1551   NOTREACHED();
   1552 }
   1553 
   1554 bool TaskManagerBrowserProcessResource::ReportsSqliteMemoryUsed() const {
   1555   return true;
   1556 }
   1557 
   1558 ////////////////////////////////////////////////////////////////////////////////
   1559 // TaskManagerBrowserProcessResourceProvider class
   1560 ////////////////////////////////////////////////////////////////////////////////
   1561 
   1562 TaskManagerBrowserProcessResourceProvider::
   1563     TaskManagerBrowserProcessResourceProvider(TaskManager* task_manager)
   1564     : updating_(false),
   1565       task_manager_(task_manager) {
   1566 }
   1567 
   1568 TaskManagerBrowserProcessResourceProvider::
   1569     ~TaskManagerBrowserProcessResourceProvider() {
   1570 }
   1571 
   1572 TaskManager::Resource* TaskManagerBrowserProcessResourceProvider::GetResource(
   1573     int origin_pid,
   1574     int render_process_host_id,
   1575     int routing_id) {
   1576   if (origin_pid || render_process_host_id != -1) {
   1577     return NULL;
   1578   }
   1579 
   1580   return &resource_;
   1581 }
   1582 
   1583 void TaskManagerBrowserProcessResourceProvider::StartUpdating() {
   1584   task_manager_->AddResource(&resource_);
   1585 }
   1586 
   1587 void TaskManagerBrowserProcessResourceProvider::StopUpdating() {
   1588 }
   1589