• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
GetMessagePrefixID(bool is_app,bool is_extension,bool is_incognito)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 ////////////////////////////////////////////////////////////////////////////////
TaskManagerRendererResource(base::ProcessHandle process,RenderViewHost * render_view_host)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 
~TaskManagerRendererResource()96 TaskManagerRendererResource::~TaskManagerRendererResource() {
97 }
98 
Refresh()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
GetWebCoreCacheStats() const111 TaskManagerRendererResource::GetWebCoreCacheStats() const {
112   return stats_;
113 }
114 
GetV8MemoryAllocated() const115 size_t TaskManagerRendererResource::GetV8MemoryAllocated() const {
116   return v8_memory_allocated_;
117 }
118 
GetV8MemoryUsed() const119 size_t TaskManagerRendererResource::GetV8MemoryUsed() const {
120   return v8_memory_used_;
121 }
122 
NotifyResourceTypeStats(const WebKit::WebCache::ResourceTypeStats & stats)123 void TaskManagerRendererResource::NotifyResourceTypeStats(
124     const WebKit::WebCache::ResourceTypeStats& stats) {
125   stats_ = stats;
126   pending_stats_update_ = false;
127 }
128 
NotifyV8HeapStats(size_t v8_memory_allocated,size_t v8_memory_used)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 
GetProcess() const136 base::ProcessHandle TaskManagerRendererResource::GetProcess() const {
137   return process_;
138 }
139 
GetType() const140 TaskManager::Resource::Type TaskManagerRendererResource::GetType() const {
141   return RENDERER;
142 }
143 
ReportsCacheStats() const144 bool TaskManagerRendererResource::ReportsCacheStats() const {
145   return true;
146 }
147 
ReportsV8MemoryStats() const148 bool TaskManagerRendererResource::ReportsV8MemoryStats() const {
149   return true;
150 }
151 
SupportNetworkUsage() const152 bool TaskManagerRendererResource::SupportNetworkUsage() const {
153   return true;
154 }
155 
156 ////////////////////////////////////////////////////////////////////////////////
157 // TaskManagerTabContentsResource class
158 ////////////////////////////////////////////////////////////////////////////////
159 
TaskManagerTabContentsResource(TabContentsWrapper * tab_contents)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 
~TaskManagerTabContentsResource()168 TaskManagerTabContentsResource::~TaskManagerTabContentsResource() {
169 }
170 
GetType() const171 TaskManager::Resource::Type TaskManagerTabContentsResource::GetType() const {
172   return tab_contents_->tab_contents()->HostsExtension() ? EXTENSION : RENDERER;
173 }
174 
GetTitle() const175 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 
GetIcon() const205 SkBitmap TaskManagerTabContentsResource::GetIcon() const {
206   return tab_contents_->tab_contents()->GetFavicon();
207 }
208 
GetTabContents() const209 TabContentsWrapper* TaskManagerTabContentsResource::GetTabContents() const {
210   return tab_contents_;
211 }
212 
GetExtension() const213 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::
TaskManagerTabContentsResourceProvider(TaskManager * task_manager)229     TaskManagerTabContentsResourceProvider(TaskManager* task_manager)
230     :  updating_(false),
231        task_manager_(task_manager) {
232 }
233 
234 TaskManagerTabContentsResourceProvider::
~TaskManagerTabContentsResourceProvider()235     ~TaskManagerTabContentsResourceProvider() {
236 }
237 
GetResource(int origin_pid,int render_process_host_id,int routing_id)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 
StartUpdating()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 
StopUpdating()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 
AddToTaskManager(TabContentsWrapper * tab_contents)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 
Add(TabContentsWrapper * tab_contents)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 
Remove(TabContentsWrapper * tab_contents)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 
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)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 
TaskManagerPrerenderResource(RenderViewHost * render_view_host)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 
~TaskManagerPrerenderResource()412 TaskManagerPrerenderResource::~TaskManagerPrerenderResource() {
413 }
414 
GetType() const415 TaskManager::Resource::Type TaskManagerPrerenderResource::GetType() const {
416   return RENDERER;
417 }
418 
GetTitle() const419 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 
GetIcon() const443 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 
TaskManagerPrerenderResourceProvider(TaskManager * task_manager)453 TaskManagerPrerenderResourceProvider::TaskManagerPrerenderResourceProvider(
454     TaskManager* task_manager)
455     :  updating_(false),
456        task_manager_(task_manager) {
457 }
458 
~TaskManagerPrerenderResourceProvider()459 TaskManagerPrerenderResourceProvider::~TaskManagerPrerenderResourceProvider() {
460   STLDeleteContainerPairSecondPointers(resources_.begin(), resources_.end());
461 }
462 
GetResource(int origin_pid,int render_process_host_id,int routing_id)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 
StartUpdating()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 
StopUpdating()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 
AddToTaskManager(const std::pair<int,int> & process_route_id_pair)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 
Add(const std::pair<int,int> & process_route_id_pair)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 
Remove(const std::pair<int,int> & process_route_id_pair)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 
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)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 
TaskManagerBackgroundContentsResource(BackgroundContents * background_contents,const string16 & application_name)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 
~TaskManagerBackgroundContentsResource()623 TaskManagerBackgroundContentsResource::~TaskManagerBackgroundContentsResource(
624     ) {
625 }
626 
GetTitle() const627 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 
GetIcon() const640 SkBitmap TaskManagerBackgroundContentsResource::GetIcon() const {
641   return *default_icon_;
642 }
643 
IsBackground() const644 bool TaskManagerBackgroundContentsResource::IsBackground() const {
645   return true;
646 }
647 
648 ////////////////////////////////////////////////////////////////////////////////
649 // TaskManagerBackgroundContentsResourceProvider class
650 ////////////////////////////////////////////////////////////////////////////////
651 
652 TaskManagerBackgroundContentsResourceProvider::
TaskManagerBackgroundContentsResourceProvider(TaskManager * task_manager)653     TaskManagerBackgroundContentsResourceProvider(TaskManager* task_manager)
654     : updating_(false),
655       task_manager_(task_manager) {
656 }
657 
658 TaskManagerBackgroundContentsResourceProvider::
~TaskManagerBackgroundContentsResourceProvider()659     ~TaskManagerBackgroundContentsResourceProvider() {
660 }
661 
662 TaskManager::Resource*
GetResource(int origin_pid,int render_process_host_id,int routing_id)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 
StartUpdating()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 
StopUpdating()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 
AddToTaskManager(BackgroundContents * background_contents,const string16 & application_name)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 
Add(BackgroundContents * contents,const string16 & application_name)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 
Remove(BackgroundContents * contents)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 
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)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 
TaskManagerChildProcessResource(const ChildProcessInfo & child_proc)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 
~TaskManagerChildProcessResource()859 TaskManagerChildProcessResource::~TaskManagerChildProcessResource() {
860 }
861 
862 // TaskManagerResource methods:
GetTitle() const863 string16 TaskManagerChildProcessResource::GetTitle() const {
864   if (title_.empty())
865     title_ = GetLocalizedTitle();
866 
867   return title_;
868 }
869 
GetIcon() const870 SkBitmap TaskManagerChildProcessResource::GetIcon() const {
871   return *default_icon_;
872 }
873 
GetProcess() const874 base::ProcessHandle TaskManagerChildProcessResource::GetProcess() const {
875   return child_process_.handle();
876 }
877 
GetType() const878 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 
SupportNetworkUsage() const908 bool TaskManagerChildProcessResource::SupportNetworkUsage() const {
909   return network_usage_support_;
910 }
911 
SetSupportNetworkUsage()912 void TaskManagerChildProcessResource::SetSupportNetworkUsage() {
913   network_usage_support_ = true;
914 }
915 
GetLocalizedTitle() const916 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::
TaskManagerChildProcessResourceProvider(TaskManager * task_manager)976     TaskManagerChildProcessResourceProvider(TaskManager* task_manager)
977     : updating_(false),
978       task_manager_(task_manager) {
979 }
980 
981 TaskManagerChildProcessResourceProvider::
~TaskManagerChildProcessResourceProvider()982     ~TaskManagerChildProcessResourceProvider() {
983 }
984 
GetResource(int origin_pid,int render_process_host_id,int routing_id)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 
StartUpdating()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 
StopUpdating()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 
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)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 
Add(const ChildProcessInfo & child_process_info)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 
Remove(const ChildProcessInfo & child_process_info)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 
AddToTaskManager(const ChildProcessInfo & child_process_info)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.
RetrieveChildProcessInfo()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.
ChildProcessInfoRetreived()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 
TaskManagerExtensionProcessResource(ExtensionHost * extension_host)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 
~TaskManagerExtensionProcessResource()1152 TaskManagerExtensionProcessResource::~TaskManagerExtensionProcessResource() {
1153 }
1154 
GetTitle() const1155 string16 TaskManagerExtensionProcessResource::GetTitle() const {
1156   return title_;
1157 }
1158 
GetIcon() const1159 SkBitmap TaskManagerExtensionProcessResource::GetIcon() const {
1160   return *default_icon_;
1161 }
1162 
GetProcess() const1163 base::ProcessHandle TaskManagerExtensionProcessResource::GetProcess() const {
1164   return process_handle_;
1165 }
1166 
1167 TaskManager::Resource::Type
GetType() const1168 TaskManagerExtensionProcessResource::GetType() const {
1169   return EXTENSION;
1170 }
1171 
SupportNetworkUsage() const1172 bool TaskManagerExtensionProcessResource::SupportNetworkUsage() const {
1173   return true;
1174 }
1175 
SetSupportNetworkUsage()1176 void TaskManagerExtensionProcessResource::SetSupportNetworkUsage() {
1177   NOTREACHED();
1178 }
1179 
GetExtension() const1180 const Extension* TaskManagerExtensionProcessResource::GetExtension() const {
1181   return extension_host_->extension();
1182 }
1183 
IsBackground() const1184 bool TaskManagerExtensionProcessResource::IsBackground() const {
1185   return extension_host_->GetRenderViewType() ==
1186       ViewType::EXTENSION_BACKGROUND_PAGE;
1187 }
1188 
1189 ////////////////////////////////////////////////////////////////////////////////
1190 // TaskManagerExtensionProcessResourceProvider class
1191 ////////////////////////////////////////////////////////////////////////////////
1192 
1193 TaskManagerExtensionProcessResourceProvider::
TaskManagerExtensionProcessResourceProvider(TaskManager * task_manager)1194     TaskManagerExtensionProcessResourceProvider(TaskManager* task_manager)
1195     : task_manager_(task_manager),
1196       updating_(false) {
1197 }
1198 
1199 TaskManagerExtensionProcessResourceProvider::
~TaskManagerExtensionProcessResourceProvider()1200     ~TaskManagerExtensionProcessResourceProvider() {
1201 }
1202 
GetResource(int origin_pid,int render_process_host_id,int routing_id)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 
StartUpdating()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 
StopUpdating()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 
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)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 
AddToTaskManager(ExtensionHost * extension_host)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 
RemoveFromTaskManager(ExtensionHost * extension_host)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 
TaskManagerNotificationResource(BalloonHost * balloon_host)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 
~TaskManagerNotificationResource()1350 TaskManagerNotificationResource::~TaskManagerNotificationResource() {
1351 }
1352 
GetTitle() const1353 string16 TaskManagerNotificationResource::GetTitle() const {
1354   return title_;
1355 }
1356 
GetIcon() const1357 SkBitmap TaskManagerNotificationResource::GetIcon() const {
1358   return *default_icon_;
1359 }
1360 
GetProcess() const1361 base::ProcessHandle TaskManagerNotificationResource::GetProcess() const {
1362   return process_handle_;
1363 }
1364 
GetType() const1365 TaskManager::Resource::Type TaskManagerNotificationResource::GetType() const {
1366   return NOTIFICATION;
1367 }
1368 
SupportNetworkUsage() const1369 bool TaskManagerNotificationResource::SupportNetworkUsage() const {
1370   return false;
1371 }
1372 
1373 ////////////////////////////////////////////////////////////////////////////////
1374 // TaskManagerNotificationResourceProvider class
1375 ////////////////////////////////////////////////////////////////////////////////
1376 
1377 TaskManagerNotificationResourceProvider::
TaskManagerNotificationResourceProvider(TaskManager * task_manager)1378     TaskManagerNotificationResourceProvider(TaskManager* task_manager)
1379     : task_manager_(task_manager),
1380       updating_(false) {
1381 }
1382 
1383 TaskManagerNotificationResourceProvider::
~TaskManagerNotificationResourceProvider()1384     ~TaskManagerNotificationResourceProvider() {
1385 }
1386 
GetResource(int origin_pid,int render_process_host_id,int routing_id)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 
StartUpdating()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 
StopUpdating()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 
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)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 
AddToTaskManager(BalloonHost * balloon_host)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 
RemoveFromTaskManager(BalloonHost * balloon_host)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 
TaskManagerBrowserProcessResource()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 
~TaskManagerBrowserProcessResource()1518 TaskManagerBrowserProcessResource::~TaskManagerBrowserProcessResource() {
1519   base::CloseProcessHandle(process_);
1520 }
1521 
1522 // TaskManagerResource methods:
GetTitle() const1523 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 
GetIcon() const1530 SkBitmap TaskManagerBrowserProcessResource::GetIcon() const {
1531   return *default_icon_;
1532 }
1533 
SqliteMemoryUsedBytes() const1534 size_t TaskManagerBrowserProcessResource::SqliteMemoryUsedBytes() const {
1535   return static_cast<size_t>(sqlite3_memory_used());
1536 }
1537 
GetProcess() const1538 base::ProcessHandle TaskManagerBrowserProcessResource::GetProcess() const {
1539   return base::GetCurrentProcessHandle();  // process_;
1540 }
1541 
GetType() const1542 TaskManager::Resource::Type TaskManagerBrowserProcessResource::GetType() const {
1543   return BROWSER;
1544 }
1545 
SupportNetworkUsage() const1546 bool TaskManagerBrowserProcessResource::SupportNetworkUsage() const {
1547   return true;
1548 }
1549 
SetSupportNetworkUsage()1550 void TaskManagerBrowserProcessResource::SetSupportNetworkUsage() {
1551   NOTREACHED();
1552 }
1553 
ReportsSqliteMemoryUsed() const1554 bool TaskManagerBrowserProcessResource::ReportsSqliteMemoryUsed() const {
1555   return true;
1556 }
1557 
1558 ////////////////////////////////////////////////////////////////////////////////
1559 // TaskManagerBrowserProcessResourceProvider class
1560 ////////////////////////////////////////////////////////////////////////////////
1561 
1562 TaskManagerBrowserProcessResourceProvider::
TaskManagerBrowserProcessResourceProvider(TaskManager * task_manager)1563     TaskManagerBrowserProcessResourceProvider(TaskManager* task_manager)
1564     : updating_(false),
1565       task_manager_(task_manager) {
1566 }
1567 
1568 TaskManagerBrowserProcessResourceProvider::
~TaskManagerBrowserProcessResourceProvider()1569     ~TaskManagerBrowserProcessResourceProvider() {
1570 }
1571 
GetResource(int origin_pid,int render_process_host_id,int routing_id)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 
StartUpdating()1583 void TaskManagerBrowserProcessResourceProvider::StartUpdating() {
1584   task_manager_->AddResource(&resource_);
1585 }
1586 
StopUpdating()1587 void TaskManagerBrowserProcessResourceProvider::StopUpdating() {
1588 }
1589