task_manager_resource_providers.cc revision 201ade2fbba22bfb27ae029f4d23fca6ded109a0
1// Copyright (c) 2010 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 "build/build_config.h"
8
9#include "app/l10n_util.h"
10#include "app/resource_bundle.h"
11#include "base/basictypes.h"
12#include "base/file_version_info.h"
13#include "base/i18n/rtl.h"
14#include "base/process_util.h"
15#include "base/stl_util-inl.h"
16#include "base/string_util.h"
17#include "base/thread.h"
18#include "base/utf_string_conversions.h"
19#include "chrome/app/chrome_command_ids.h"
20#include "chrome/browser/background_contents_service.h"
21#include "chrome/browser/browser_child_process_host.h"
22#include "chrome/browser/browser_list.h"
23#include "chrome/browser/browser_process.h"
24#include "chrome/browser/browser_thread.h"
25#include "chrome/browser/extensions/extension_host.h"
26#include "chrome/browser/extensions/extension_process_manager.h"
27#include "chrome/browser/extensions/extensions_service.h"
28#include "chrome/browser/notifications/balloon_collection.h"
29#include "chrome/browser/notifications/balloon_host.h"
30#include "chrome/browser/notifications/notification_ui_manager.h"
31#include "chrome/browser/profile_manager.h"
32#include "chrome/browser/renderer_host/render_process_host.h"
33#include "chrome/browser/renderer_host/render_view_host.h"
34#include "chrome/browser/renderer_host/resource_message_filter.h"
35#include "chrome/browser/tab_contents/background_contents.h"
36#include "chrome/browser/tab_contents/tab_contents.h"
37#include "chrome/browser/tab_contents/tab_util.h"
38#include "chrome/common/extensions/extension.h"
39#include "chrome/common/notification_service.h"
40#include "chrome/common/render_messages.h"
41#include "chrome/common/sqlite_utils.h"
42#include "grit/generated_resources.h"
43#include "grit/theme_resources.h"
44
45#if defined(OS_MACOSX)
46#include "skia/ext/skia_utils_mac.h"
47#endif
48#if defined(OS_WIN)
49#include "chrome/browser/app_icon_win.h"
50#include "gfx/icon_util.h"
51#endif  // defined(OS_WIN)
52
53
54////////////////////////////////////////////////////////////////////////////////
55// TaskManagerRendererResource class
56////////////////////////////////////////////////////////////////////////////////
57TaskManagerRendererResource::TaskManagerRendererResource(
58    base::ProcessHandle process, RenderViewHost* render_view_host)
59    : process_(process),
60      render_view_host_(render_view_host),
61      pending_stats_update_(false),
62      v8_memory_allocated_(0),
63      v8_memory_used_(0),
64      pending_v8_memory_allocated_update_(false) {
65  // We cache the process and pid as when a Tab/BackgroundContents is closed the
66  // process reference becomes NULL and the TaskManager still needs it.
67  pid_ = base::GetProcId(process_);
68  stats_.images.size = 0;
69  stats_.cssStyleSheets.size = 0;
70  stats_.scripts.size = 0;
71  stats_.xslStyleSheets.size = 0;
72  stats_.fonts.size = 0;
73}
74
75TaskManagerRendererResource::~TaskManagerRendererResource() {
76}
77
78void TaskManagerRendererResource::Refresh() {
79  if (!pending_stats_update_) {
80    render_view_host_->Send(new ViewMsg_GetCacheResourceStats);
81    pending_stats_update_ = true;
82  }
83  if (!pending_v8_memory_allocated_update_) {
84    render_view_host_->Send(new ViewMsg_GetV8HeapStats);
85    pending_v8_memory_allocated_update_ = true;
86  }
87}
88
89WebKit::WebCache::ResourceTypeStats
90TaskManagerRendererResource::GetWebCoreCacheStats() const {
91  return stats_;
92}
93
94size_t TaskManagerRendererResource::GetV8MemoryAllocated() const {
95  return v8_memory_allocated_;
96}
97
98size_t TaskManagerRendererResource::GetV8MemoryUsed() const {
99  return v8_memory_used_;
100}
101
102void TaskManagerRendererResource::NotifyResourceTypeStats(
103    const WebKit::WebCache::ResourceTypeStats& stats) {
104  stats_ = stats;
105  pending_stats_update_ = false;
106}
107
108void TaskManagerRendererResource::NotifyV8HeapStats(
109    size_t v8_memory_allocated, size_t v8_memory_used) {
110  v8_memory_allocated_ = v8_memory_allocated;
111  v8_memory_used_ = v8_memory_used;
112  pending_v8_memory_allocated_update_ = false;
113}
114
115base::ProcessHandle TaskManagerRendererResource::GetProcess() const {
116  return process_;
117}
118
119////////////////////////////////////////////////////////////////////////////////
120// TaskManagerTabContentsResource class
121////////////////////////////////////////////////////////////////////////////////
122
123TaskManagerTabContentsResource::TaskManagerTabContentsResource(
124    TabContents* tab_contents)
125    : TaskManagerRendererResource(
126          tab_contents->GetRenderProcessHost()->GetHandle(),
127          tab_contents->render_view_host()),
128      tab_contents_(tab_contents) {
129}
130
131TaskManagerTabContentsResource::~TaskManagerTabContentsResource() {
132}
133
134std::wstring TaskManagerTabContentsResource::GetTitle() const {
135  // Fall back on the URL if there's no title.
136  std::wstring tab_title(UTF16ToWideHack(tab_contents_->GetTitle()));
137  if (tab_title.empty()) {
138    tab_title = UTF8ToWide(tab_contents_->GetURL().spec());
139    // Force URL to be LTR.
140    tab_title = UTF16ToWide(base::i18n::GetDisplayStringInLTRDirectionality(
141        WideToUTF16(tab_title)));
142  } else {
143    // Since the tab_title will be concatenated with
144    // IDS_TASK_MANAGER_TAB_PREFIX, we need to explicitly set the tab_title to
145    // be LTR format if there is no strong RTL charater in it. Otherwise, if
146    // IDS_TASK_MANAGER_TAB_PREFIX is an RTL word, the concatenated result
147    // might be wrong. For example, http://mail.yahoo.com, whose title is
148    // "Yahoo! Mail: The best web-based Email!", without setting it explicitly
149    // as LTR format, the concatenated result will be "!Yahoo! Mail: The best
150    // web-based Email :BAT", in which the capital letters "BAT" stands for
151    // the Hebrew word for "tab".
152    base::i18n::AdjustStringForLocaleDirection(&tab_title);
153  }
154
155  return l10n_util::GetStringF(IDS_TASK_MANAGER_TAB_PREFIX, tab_title);
156}
157
158
159SkBitmap TaskManagerTabContentsResource::GetIcon() const {
160  return tab_contents_->GetFavIcon();
161}
162
163TabContents* TaskManagerTabContentsResource::GetTabContents() const {
164  return static_cast<TabContents*>(tab_contents_);
165}
166
167////////////////////////////////////////////////////////////////////////////////
168// TaskManagerTabContentsResourceProvider class
169////////////////////////////////////////////////////////////////////////////////
170
171TaskManagerTabContentsResourceProvider::
172    TaskManagerTabContentsResourceProvider(TaskManager* task_manager)
173    :  updating_(false),
174       task_manager_(task_manager) {
175}
176
177TaskManagerTabContentsResourceProvider::
178    ~TaskManagerTabContentsResourceProvider() {
179}
180
181TaskManager::Resource* TaskManagerTabContentsResourceProvider::GetResource(
182    int origin_pid,
183    int render_process_host_id,
184    int routing_id) {
185
186  TabContents* tab_contents =
187      tab_util::GetTabContentsByID(render_process_host_id, routing_id);
188  if (!tab_contents)  // Not one of our resource.
189    return NULL;
190
191  base::ProcessHandle process_handle =
192      tab_contents->GetRenderProcessHost()->GetHandle();
193  if (!process_handle) {
194    // We should not be holding on to a dead tab (it should have been removed
195    // through the NOTIFY_TAB_CONTENTS_DISCONNECTED notification.
196    NOTREACHED();
197    return NULL;
198  }
199
200  int pid = base::GetProcId(process_handle);
201  if (pid != origin_pid)
202    return NULL;
203
204  std::map<TabContents*, TaskManagerTabContentsResource*>::iterator
205      res_iter = resources_.find(tab_contents);
206  if (res_iter == resources_.end()) {
207    // Can happen if the tab was closed while a network request was being
208    // performed.
209    return NULL;
210  }
211  return res_iter->second;
212}
213
214void TaskManagerTabContentsResourceProvider::StartUpdating() {
215  DCHECK(!updating_);
216  updating_ = true;
217
218  // Add all the existing TabContents.
219  for (TabContentsIterator iterator; !iterator.done(); ++iterator)
220    Add(*iterator);
221
222  // Then we register for notifications to get new tabs.
223  registrar_.Add(this, NotificationType::TAB_CONTENTS_CONNECTED,
224                 NotificationService::AllSources());
225  registrar_.Add(this, NotificationType::TAB_CONTENTS_SWAPPED,
226                 NotificationService::AllSources());
227  registrar_.Add(this, NotificationType::TAB_CONTENTS_DISCONNECTED,
228                 NotificationService::AllSources());
229  // TAB_CONTENTS_DISCONNECTED should be enough to know when to remove a
230  // resource.  This is an attempt at mitigating a crasher that seem to
231  // indicate a resource is still referencing a deleted TabContents
232  // (http://crbug.com/7321).
233  registrar_.Add(this, NotificationType::TAB_CONTENTS_DESTROYED,
234                 NotificationService::AllSources());
235}
236
237void TaskManagerTabContentsResourceProvider::StopUpdating() {
238  DCHECK(updating_);
239  updating_ = false;
240
241  // Then we unregister for notifications to get new tabs.
242  registrar_.Remove(this, NotificationType::TAB_CONTENTS_CONNECTED,
243                    NotificationService::AllSources());
244  registrar_.Remove(this, NotificationType::TAB_CONTENTS_SWAPPED,
245                    NotificationService::AllSources());
246  registrar_.Remove(this, NotificationType::TAB_CONTENTS_DISCONNECTED,
247                    NotificationService::AllSources());
248  registrar_.Remove(this, NotificationType::TAB_CONTENTS_DESTROYED,
249                    NotificationService::AllSources());
250
251  // Delete all the resources.
252  STLDeleteContainerPairSecondPointers(resources_.begin(), resources_.end());
253
254  resources_.clear();
255}
256
257void TaskManagerTabContentsResourceProvider::AddToTaskManager(
258    TabContents* tab_contents) {
259  TaskManagerTabContentsResource* resource =
260      new TaskManagerTabContentsResource(tab_contents);
261  resources_[tab_contents] = resource;
262  task_manager_->AddResource(resource);
263}
264
265void TaskManagerTabContentsResourceProvider::Add(TabContents* tab_contents) {
266  if (!updating_)
267    return;
268
269  // Don't add dead tabs or tabs that haven't yet connected.
270  // Also ignore tabs which display extension content. We collapse
271  // all of these into one extension row.
272  if (!tab_contents->GetRenderProcessHost()->GetHandle() ||
273      !tab_contents->notify_disconnection() ||
274      tab_contents->HostsExtension()) {
275    return;
276  }
277
278  std::map<TabContents*, TaskManagerTabContentsResource*>::const_iterator
279      iter = resources_.find(tab_contents);
280  if (iter != resources_.end()) {
281    // The case may happen that we have added a TabContents as part of the
282    // iteration performed during StartUpdating() call but the notification that
283    // it has connected was not fired yet. So when the notification happens, we
284    // already know about this tab and just ignore it.
285    return;
286  }
287  AddToTaskManager(tab_contents);
288}
289
290void TaskManagerTabContentsResourceProvider::Remove(TabContents* tab_contents) {
291  if (!updating_)
292    return;
293  std::map<TabContents*, TaskManagerTabContentsResource*>::iterator
294      iter = resources_.find(tab_contents);
295  if (iter == resources_.end()) {
296    // Since TabContents are destroyed asynchronously (see TabContentsCollector
297    // in navigation_controller.cc), we can be notified of a tab being removed
298    // that we don't know.  This can happen if the user closes a tab and quickly
299    // opens the task manager, before the tab is actually destroyed.
300    return;
301  }
302
303  // Remove the resource from the Task Manager.
304  TaskManagerTabContentsResource* resource = iter->second;
305  task_manager_->RemoveResource(resource);
306  // And from the provider.
307  resources_.erase(iter);
308  // Finally, delete the resource.
309  delete resource;
310}
311
312void TaskManagerTabContentsResourceProvider::Observe(NotificationType type,
313    const NotificationSource& source,
314    const NotificationDetails& details) {
315  switch (type.value) {
316    case NotificationType::TAB_CONTENTS_CONNECTED:
317      Add(Source<TabContents>(source).ptr());
318      break;
319    case NotificationType::TAB_CONTENTS_SWAPPED:
320      Remove(Source<TabContents>(source).ptr());
321      Add(Source<TabContents>(source).ptr());
322      break;
323    case NotificationType::TAB_CONTENTS_DESTROYED:
324      // If this DCHECK is triggered, it could explain http://crbug.com/7321.
325      DCHECK(resources_.find(Source<TabContents>(source).ptr()) ==
326             resources_.end()) << "TAB_CONTENTS_DESTROYED with no associated "
327                                  "TAB_CONTENTS_DISCONNECTED";
328      // Fall through.
329    case NotificationType::TAB_CONTENTS_DISCONNECTED:
330      Remove(Source<TabContents>(source).ptr());
331      break;
332    default:
333      NOTREACHED() << "Unexpected notification.";
334      return;
335  }
336}
337
338////////////////////////////////////////////////////////////////////////////////
339// TaskManagerBackgroundContentsResource class
340////////////////////////////////////////////////////////////////////////////////
341
342SkBitmap* TaskManagerBackgroundContentsResource::default_icon_ = NULL;
343
344TaskManagerBackgroundContentsResource::TaskManagerBackgroundContentsResource(
345    BackgroundContents* background_contents,
346    const std::wstring& application_name)
347    : TaskManagerRendererResource(
348          background_contents->render_view_host()->process()->GetHandle(),
349          background_contents->render_view_host()),
350      background_contents_(background_contents),
351      application_name_(application_name) {
352  // Just use the same icon that other extension resources do.
353  // TODO(atwilson): Use the favicon when that's available.
354  if (!default_icon_) {
355    ResourceBundle& rb = ResourceBundle::GetSharedInstance();
356    default_icon_ = rb.GetBitmapNamed(IDR_PLUGIN);
357  }
358  // Ensure that the string has the appropriate direction markers (see comment
359  // in TaskManagerTabContentsResource::GetTitle()).
360  base::i18n::AdjustStringForLocaleDirection(&application_name_);
361}
362
363TaskManagerBackgroundContentsResource::~TaskManagerBackgroundContentsResource(
364    ) {
365}
366
367std::wstring TaskManagerBackgroundContentsResource::GetTitle() const {
368  std::wstring title = application_name_;
369
370  if (title.empty()) {
371    // No title (can't locate the parent app for some reason) so just display
372    // the URL (properly forced to be LTR).
373    title = UTF16ToWide(base::i18n::GetDisplayStringInLTRDirectionality(
374        UTF8ToUTF16(background_contents_->GetURL().spec())));
375  }
376  return l10n_util::GetStringF(IDS_TASK_MANAGER_BACKGROUND_PREFIX, title);
377}
378
379
380SkBitmap TaskManagerBackgroundContentsResource::GetIcon() const {
381  return *default_icon_;
382}
383
384bool TaskManagerBackgroundContentsResource::IsBackground() const {
385  return true;
386}
387
388////////////////////////////////////////////////////////////////////////////////
389// TaskManagerBackgroundContentsResourceProvider class
390////////////////////////////////////////////////////////////////////////////////
391
392TaskManagerBackgroundContentsResourceProvider::
393    TaskManagerBackgroundContentsResourceProvider(TaskManager* task_manager)
394    : updating_(false),
395      task_manager_(task_manager) {
396}
397
398TaskManagerBackgroundContentsResourceProvider::
399    ~TaskManagerBackgroundContentsResourceProvider() {
400}
401
402TaskManager::Resource*
403TaskManagerBackgroundContentsResourceProvider::GetResource(
404    int origin_pid,
405    int render_process_host_id,
406    int routing_id) {
407
408  BackgroundContents* contents = BackgroundContents::GetBackgroundContentsByID(
409      render_process_host_id, routing_id);
410  if (!contents)  // This resource no longer exists.
411    return NULL;
412
413  base::ProcessHandle process_handle =
414      contents->render_view_host()->process()->GetHandle();
415  if (!process_handle) // Process crashed.
416    return NULL;
417
418  int pid = base::GetProcId(process_handle);
419  if (pid != origin_pid)
420    return NULL;
421
422  std::map<BackgroundContents*,
423      TaskManagerBackgroundContentsResource*>::iterator res_iter =
424      resources_.find(contents);
425  if (res_iter == resources_.end())
426    // Can happen if the page went away while a network request was being
427    // performed.
428    return NULL;
429
430  return res_iter->second;
431}
432
433void TaskManagerBackgroundContentsResourceProvider::StartUpdating() {
434  DCHECK(!updating_);
435  updating_ = true;
436
437  // Add all the existing BackgroundContents from every profile.
438  ProfileManager* profile_manager = g_browser_process->profile_manager();
439  for (ProfileManager::const_iterator it = profile_manager->begin();
440       it != profile_manager->end(); ++it) {
441    BackgroundContentsService* background_contents_service =
442        (*it)->GetBackgroundContentsService();
443    ExtensionsService* extensions_service = (*it)->GetExtensionsService();
444    std::vector<BackgroundContents*> contents =
445        background_contents_service->GetBackgroundContents();
446    for (std::vector<BackgroundContents*>::iterator iterator = contents.begin();
447         iterator != contents.end(); ++iterator) {
448      std::wstring application_name;
449      // Lookup the name from the parent extension.
450      if (extensions_service) {
451        const string16& application_id =
452            background_contents_service->GetParentApplicationId(*iterator);
453        const Extension* extension = extensions_service->GetExtensionById(
454            UTF16ToUTF8(application_id), false);
455        if (extension)
456          application_name = UTF8ToWide(extension->name());
457      }
458      Add(*iterator, application_name);
459    }
460  }
461
462  // Then we register for notifications to get new BackgroundContents.
463  registrar_.Add(this, NotificationType::BACKGROUND_CONTENTS_OPENED,
464                 NotificationService::AllSources());
465  registrar_.Add(this, NotificationType::BACKGROUND_CONTENTS_NAVIGATED,
466                 NotificationService::AllSources());
467  registrar_.Add(this, NotificationType::BACKGROUND_CONTENTS_DELETED,
468                 NotificationService::AllSources());
469}
470
471void TaskManagerBackgroundContentsResourceProvider::StopUpdating() {
472  DCHECK(updating_);
473  updating_ = false;
474
475  // Unregister for notifications
476  registrar_.Remove(this, NotificationType::BACKGROUND_CONTENTS_OPENED,
477                    NotificationService::AllSources());
478  registrar_.Remove(this, NotificationType::BACKGROUND_CONTENTS_NAVIGATED,
479                    NotificationService::AllSources());
480  registrar_.Remove(this, NotificationType::BACKGROUND_CONTENTS_DELETED,
481                    NotificationService::AllSources());
482
483  // Delete all the resources.
484  STLDeleteContainerPairSecondPointers(resources_.begin(), resources_.end());
485
486  resources_.clear();
487}
488
489void TaskManagerBackgroundContentsResourceProvider::AddToTaskManager(
490    BackgroundContents* background_contents,
491    const std::wstring& application_name) {
492  TaskManagerBackgroundContentsResource* resource =
493      new TaskManagerBackgroundContentsResource(background_contents,
494                                                application_name);
495  resources_[background_contents] = resource;
496  task_manager_->AddResource(resource);
497}
498
499void TaskManagerBackgroundContentsResourceProvider::Add(
500    BackgroundContents* contents, const std::wstring& application_name) {
501  if (!updating_)
502    return;
503
504  // Don't add contents whose process is dead.
505  if (!contents->render_view_host()->process()->GetHandle())
506    return;
507
508  // Should never add the same BackgroundContents twice.
509  DCHECK(resources_.find(contents) == resources_.end());
510  AddToTaskManager(contents, application_name);
511}
512
513void TaskManagerBackgroundContentsResourceProvider::Remove(
514    BackgroundContents* contents) {
515  if (!updating_)
516    return;
517  std::map<BackgroundContents*,
518      TaskManagerBackgroundContentsResource*>::iterator iter =
519      resources_.find(contents);
520  DCHECK(iter != resources_.end());
521
522  // Remove the resource from the Task Manager.
523  TaskManagerBackgroundContentsResource* resource = iter->second;
524  task_manager_->RemoveResource(resource);
525  // And from the provider.
526  resources_.erase(iter);
527  // Finally, delete the resource.
528  delete resource;
529}
530
531void TaskManagerBackgroundContentsResourceProvider::Observe(
532    NotificationType type,
533    const NotificationSource& source,
534    const NotificationDetails& details) {
535  switch (type.value) {
536    case NotificationType::BACKGROUND_CONTENTS_OPENED: {
537      // Get the name from the parent application. If no parent application is
538      // found, just pass an empty string - BackgroundContentsResource::GetTitle
539      // will display the URL instead in this case. This should never happen
540      // except in rare cases when an extension is being unloaded or chrome is
541      // exiting while the task manager is displayed.
542      std::wstring application_name;
543      ExtensionsService* service =
544          Source<Profile>(source)->GetExtensionsService();
545      if (service) {
546        std::string application_id = UTF16ToUTF8(
547            Details<BackgroundContentsOpenedDetails>(details)->application_id);
548        const Extension* extension =
549            service->GetExtensionById(application_id, false);
550        // Extension can be NULL when running unit tests.
551        if (extension)
552          application_name = UTF8ToWide(extension->name());
553      }
554      Add(Details<BackgroundContentsOpenedDetails>(details)->contents,
555          application_name);
556      // Opening a new BackgroundContents needs to force the display to refresh
557      // (applications may now be considered "background" that weren't before).
558      task_manager_->ModelChanged();
559      break;
560    }
561    case NotificationType::BACKGROUND_CONTENTS_NAVIGATED: {
562      BackgroundContents* contents = Details<BackgroundContents>(details).ptr();
563      // Should never get a NAVIGATED before OPENED.
564      DCHECK(resources_.find(contents) != resources_.end());
565      // Preserve the application name.
566      std::wstring application_name(
567          resources_.find(contents)->second->application_name());
568      Remove(contents);
569      Add(contents, application_name);
570      break;
571    }
572    case NotificationType::BACKGROUND_CONTENTS_DELETED:
573      Remove(Details<BackgroundContents>(details).ptr());
574      // Closing a BackgroundContents needs to force the display to refresh
575      // (applications may now be considered "foreground" that weren't before).
576      task_manager_->ModelChanged();
577      break;
578    default:
579      NOTREACHED() << "Unexpected notification.";
580      return;
581  }
582}
583
584////////////////////////////////////////////////////////////////////////////////
585// TaskManagerChildProcessResource class
586////////////////////////////////////////////////////////////////////////////////
587SkBitmap* TaskManagerChildProcessResource::default_icon_ = NULL;
588
589TaskManagerChildProcessResource::TaskManagerChildProcessResource(
590    const ChildProcessInfo& child_proc)
591    : child_process_(child_proc),
592      title_(),
593      network_usage_support_(false) {
594  // We cache the process id because it's not cheap to calculate, and it won't
595  // be available when we get the plugin disconnected notification.
596  pid_ = child_proc.id();
597  if (!default_icon_) {
598    ResourceBundle& rb = ResourceBundle::GetSharedInstance();
599    default_icon_ = rb.GetBitmapNamed(IDR_PLUGIN);
600    // TODO(jabdelmalek): use different icon for web workers.
601  }
602}
603
604TaskManagerChildProcessResource::~TaskManagerChildProcessResource() {
605}
606
607// TaskManagerResource methods:
608std::wstring TaskManagerChildProcessResource::GetTitle() const {
609  if (title_.empty())
610    title_ = UTF16ToWideHack(child_process_.GetLocalizedTitle());
611
612  return title_;
613}
614
615SkBitmap TaskManagerChildProcessResource::GetIcon() const {
616  return *default_icon_;
617}
618
619base::ProcessHandle TaskManagerChildProcessResource::GetProcess() const {
620  return child_process_.handle();
621}
622
623TaskManager::Resource::Type TaskManagerChildProcessResource::GetType() const {
624  // Translate types to TaskManager::ResourceType, since ChildProcessInfo's type
625  // is not available for all TaskManager resources.
626  switch (child_process_.type()) {
627    case ChildProcessInfo::BROWSER_PROCESS:
628      return TaskManager::Resource::BROWSER;
629    case ChildProcessInfo::RENDER_PROCESS:
630      return TaskManager::Resource::RENDERER;
631    case ChildProcessInfo::PLUGIN_PROCESS:
632      return TaskManager::Resource::PLUGIN;
633    case ChildProcessInfo::WORKER_PROCESS:
634      return TaskManager::Resource::WORKER;
635    case ChildProcessInfo::NACL_LOADER_PROCESS:
636    case ChildProcessInfo::NACL_BROKER_PROCESS:
637      return TaskManager::Resource::NACL;
638    case ChildProcessInfo::UTILITY_PROCESS:
639      return TaskManager::Resource::UTILITY;
640    case ChildProcessInfo::PROFILE_IMPORT_PROCESS:
641      return TaskManager::Resource::PROFILE_IMPORT;
642    case ChildProcessInfo::ZYGOTE_PROCESS:
643      return TaskManager::Resource::ZYGOTE;
644    case ChildProcessInfo::SANDBOX_HELPER_PROCESS:
645      return TaskManager::Resource::SANDBOX_HELPER;
646    case ChildProcessInfo::GPU_PROCESS:
647      return TaskManager::Resource::GPU;
648    default:
649      return TaskManager::Resource::UNKNOWN;
650  }
651}
652
653////////////////////////////////////////////////////////////////////////////////
654// TaskManagerChildProcessResourceProvider class
655////////////////////////////////////////////////////////////////////////////////
656
657TaskManagerChildProcessResourceProvider::
658    TaskManagerChildProcessResourceProvider(TaskManager* task_manager)
659    : updating_(false),
660      task_manager_(task_manager) {
661}
662
663TaskManagerChildProcessResourceProvider::
664    ~TaskManagerChildProcessResourceProvider() {
665}
666
667TaskManager::Resource* TaskManagerChildProcessResourceProvider::GetResource(
668    int origin_pid,
669    int render_process_host_id,
670    int routing_id) {
671  std::map<int, TaskManagerChildProcessResource*>::iterator iter =
672      pid_to_resources_.find(origin_pid);
673  if (iter != pid_to_resources_.end())
674    return iter->second;
675  else
676    return NULL;
677}
678
679void TaskManagerChildProcessResourceProvider::StartUpdating() {
680  DCHECK(!updating_);
681  updating_ = true;
682
683  // Register for notifications to get new child processes.
684  registrar_.Add(this, NotificationType::CHILD_PROCESS_HOST_CONNECTED,
685                 NotificationService::AllSources());
686  registrar_.Add(this, NotificationType::CHILD_PROCESS_HOST_DISCONNECTED,
687                 NotificationService::AllSources());
688
689  // Get the existing child processes.
690  BrowserThread::PostTask(
691      BrowserThread::IO, FROM_HERE,
692      NewRunnableMethod(
693          this,
694          &TaskManagerChildProcessResourceProvider::RetrieveChildProcessInfo));
695}
696
697void TaskManagerChildProcessResourceProvider::StopUpdating() {
698  DCHECK(updating_);
699  updating_ = false;
700
701  // Unregister for notifications to get new plugin processes.
702  registrar_.Remove(this, NotificationType::CHILD_PROCESS_HOST_CONNECTED,
703                    NotificationService::AllSources());
704  registrar_.Remove(this,
705                    NotificationType::CHILD_PROCESS_HOST_DISCONNECTED,
706                    NotificationService::AllSources());
707
708  // Delete all the resources.
709  STLDeleteContainerPairSecondPointers(resources_.begin(), resources_.end());
710
711  resources_.clear();
712  pid_to_resources_.clear();
713  existing_child_process_info_.clear();
714}
715
716void TaskManagerChildProcessResourceProvider::Observe(
717    NotificationType type,
718    const NotificationSource& source,
719    const NotificationDetails& details) {
720  switch (type.value) {
721    case NotificationType::CHILD_PROCESS_HOST_CONNECTED:
722      Add(*Details<ChildProcessInfo>(details).ptr());
723      break;
724    case NotificationType::CHILD_PROCESS_HOST_DISCONNECTED:
725      Remove(*Details<ChildProcessInfo>(details).ptr());
726      break;
727    default:
728      NOTREACHED() << "Unexpected notification.";
729      return;
730  }
731}
732
733void TaskManagerChildProcessResourceProvider::Add(
734    const ChildProcessInfo& child_process_info) {
735  if (!updating_)
736    return;
737  std::map<ChildProcessInfo, TaskManagerChildProcessResource*>::
738      const_iterator iter = resources_.find(child_process_info);
739  if (iter != resources_.end()) {
740    // The case may happen that we have added a child_process_info as part of
741    // the iteration performed during StartUpdating() call but the notification
742    // that it has connected was not fired yet. So when the notification
743    // happens, we already know about this plugin and just ignore it.
744    return;
745  }
746  AddToTaskManager(child_process_info);
747}
748
749void TaskManagerChildProcessResourceProvider::Remove(
750    const ChildProcessInfo& child_process_info) {
751  if (!updating_)
752    return;
753  std::map<ChildProcessInfo, TaskManagerChildProcessResource*>
754      ::iterator iter = resources_.find(child_process_info);
755  if (iter == resources_.end()) {
756    // ChildProcessInfo disconnection notifications are asynchronous, so we
757    // might be notified for a plugin we don't know anything about (if it was
758    // closed before the task manager was shown and destroyed after that).
759    return;
760  }
761  // Remove the resource from the Task Manager.
762  TaskManagerChildProcessResource* resource = iter->second;
763  task_manager_->RemoveResource(resource);
764  // Remove it from the provider.
765  resources_.erase(iter);
766  // Remove it from our pid map.
767  std::map<int, TaskManagerChildProcessResource*>::iterator pid_iter =
768      pid_to_resources_.find(resource->process_id());
769  DCHECK(pid_iter != pid_to_resources_.end());
770  if (pid_iter != pid_to_resources_.end())
771    pid_to_resources_.erase(pid_iter);
772
773  // Finally, delete the resource.
774  delete resource;
775}
776
777void TaskManagerChildProcessResourceProvider::AddToTaskManager(
778    const ChildProcessInfo& child_process_info) {
779  TaskManagerChildProcessResource* resource =
780      new TaskManagerChildProcessResource(child_process_info);
781  resources_[child_process_info] = resource;
782  pid_to_resources_[resource->process_id()] = resource;
783  task_manager_->AddResource(resource);
784}
785
786// The ChildProcessInfo::Iterator has to be used from the IO thread.
787void TaskManagerChildProcessResourceProvider::RetrieveChildProcessInfo() {
788  for (BrowserChildProcessHost::Iterator iter; !iter.Done(); ++iter) {
789    // Only add processes which are already started, since we need their handle.
790    if ((*iter)->handle() != base::kNullProcessHandle)
791      existing_child_process_info_.push_back(**iter);
792  }
793  // Now notify the UI thread that we have retrieved information about child
794  // processes.
795  BrowserThread::PostTask(
796      BrowserThread::UI, FROM_HERE,
797      NewRunnableMethod(this,
798          &TaskManagerChildProcessResourceProvider::ChildProcessInfoRetreived));
799}
800
801// This is called on the UI thread.
802void TaskManagerChildProcessResourceProvider::ChildProcessInfoRetreived() {
803  std::vector<ChildProcessInfo>::const_iterator iter;
804  for (iter = existing_child_process_info_.begin();
805       iter != existing_child_process_info_.end(); ++iter) {
806    Add(*iter);
807  }
808  existing_child_process_info_.clear();
809}
810
811////////////////////////////////////////////////////////////////////////////////
812// TaskManagerExtensionProcessResource class
813////////////////////////////////////////////////////////////////////////////////
814
815SkBitmap* TaskManagerExtensionProcessResource::default_icon_ = NULL;
816
817TaskManagerExtensionProcessResource::TaskManagerExtensionProcessResource(
818    ExtensionHost* extension_host)
819    : extension_host_(extension_host) {
820  if (!default_icon_) {
821    ResourceBundle& rb = ResourceBundle::GetSharedInstance();
822    default_icon_ = rb.GetBitmapNamed(IDR_PLUGIN);
823  }
824  process_handle_ = extension_host_->render_process_host()->GetHandle();
825  pid_ = base::GetProcId(process_handle_);
826  std::wstring extension_name(UTF8ToWide(GetExtension()->name()));
827  DCHECK(!extension_name.empty());
828
829  int message_id =
830      GetExtension()->is_app() ?
831          (extension_host_->profile()->IsOffTheRecord() ?
832              IDS_TASK_MANAGER_APP_INCOGNITO_PREFIX :
833              IDS_TASK_MANAGER_APP_PREFIX) :
834          (extension_host_->profile()->IsOffTheRecord() ?
835              IDS_TASK_MANAGER_EXTENSION_INCOGNITO_PREFIX :
836              IDS_TASK_MANAGER_EXTENSION_PREFIX);
837  title_ = l10n_util::GetStringF(message_id, extension_name);
838}
839
840TaskManagerExtensionProcessResource::~TaskManagerExtensionProcessResource() {
841}
842
843std::wstring TaskManagerExtensionProcessResource::GetTitle() const {
844  return title_;
845}
846
847SkBitmap TaskManagerExtensionProcessResource::GetIcon() const {
848  return *default_icon_;
849}
850
851base::ProcessHandle TaskManagerExtensionProcessResource::GetProcess() const {
852  return process_handle_;
853}
854
855const Extension* TaskManagerExtensionProcessResource::GetExtension() const {
856  return extension_host_->extension();
857}
858
859bool TaskManagerExtensionProcessResource::IsBackground() const {
860  return extension_host_->GetRenderViewType() ==
861      ViewType::EXTENSION_BACKGROUND_PAGE;
862}
863
864////////////////////////////////////////////////////////////////////////////////
865// TaskManagerExtensionProcessResourceProvider class
866////////////////////////////////////////////////////////////////////////////////
867
868TaskManagerExtensionProcessResourceProvider::
869    TaskManagerExtensionProcessResourceProvider(TaskManager* task_manager)
870    : task_manager_(task_manager),
871      updating_(false) {
872}
873
874TaskManagerExtensionProcessResourceProvider::
875    ~TaskManagerExtensionProcessResourceProvider() {
876}
877
878TaskManager::Resource* TaskManagerExtensionProcessResourceProvider::GetResource(
879    int origin_pid,
880    int render_process_host_id,
881    int routing_id) {
882  std::map<int, TaskManagerExtensionProcessResource*>::iterator iter =
883      pid_to_resources_.find(origin_pid);
884  if (iter != pid_to_resources_.end())
885    return iter->second;
886  else
887    return NULL;
888}
889
890void TaskManagerExtensionProcessResourceProvider::StartUpdating() {
891  DCHECK(!updating_);
892  updating_ = true;
893
894  // Add all the existing ExtensionHosts.
895  ProfileManager* profile_manager = g_browser_process->profile_manager();
896  for (ProfileManager::const_iterator it = profile_manager->begin();
897       it != profile_manager->end(); ++it) {
898    ExtensionProcessManager* process_manager =
899        (*it)->GetExtensionProcessManager();
900    if (process_manager) {
901      ExtensionProcessManager::const_iterator jt;
902      for (jt = process_manager->begin(); jt != process_manager->end(); ++jt)
903        AddToTaskManager(*jt);
904    }
905
906    // If we have an incognito profile active, include the split-mode incognito
907    // extensions.
908    if (BrowserList::IsOffTheRecordSessionActive()) {
909      ExtensionProcessManager* process_manager =
910          (*it)->GetOffTheRecordProfile()->GetExtensionProcessManager();
911      if (process_manager) {
912      ExtensionProcessManager::const_iterator jt;
913      for (jt = process_manager->begin(); jt != process_manager->end(); ++jt)
914        AddToTaskManager(*jt);
915      }
916    }
917  }
918
919  // Register for notifications about extension process changes.
920  registrar_.Add(this, NotificationType::EXTENSION_PROCESS_CREATED,
921                 NotificationService::AllSources());
922  registrar_.Add(this, NotificationType::EXTENSION_PROCESS_TERMINATED,
923                 NotificationService::AllSources());
924  registrar_.Add(this, NotificationType::EXTENSION_HOST_DESTROYED,
925                 NotificationService::AllSources());
926}
927
928void TaskManagerExtensionProcessResourceProvider::StopUpdating() {
929  DCHECK(updating_);
930  updating_ = false;
931
932  // Unregister for notifications about extension process changes.
933  registrar_.Remove(this, NotificationType::EXTENSION_PROCESS_CREATED,
934                    NotificationService::AllSources());
935  registrar_.Remove(this, NotificationType::EXTENSION_PROCESS_TERMINATED,
936                    NotificationService::AllSources());
937  registrar_.Remove(this, NotificationType::EXTENSION_HOST_DESTROYED,
938                    NotificationService::AllSources());
939
940  // Delete all the resources.
941  STLDeleteContainerPairSecondPointers(resources_.begin(), resources_.end());
942
943  resources_.clear();
944  pid_to_resources_.clear();
945}
946
947void TaskManagerExtensionProcessResourceProvider::Observe(
948    NotificationType type,
949    const NotificationSource& source,
950    const NotificationDetails& details) {
951  switch (type.value) {
952    case NotificationType::EXTENSION_PROCESS_CREATED:
953      AddToTaskManager(Details<ExtensionHost>(details).ptr());
954      break;
955    case NotificationType::EXTENSION_PROCESS_TERMINATED:
956    case NotificationType::EXTENSION_HOST_DESTROYED:
957      RemoveFromTaskManager(Details<ExtensionHost>(details).ptr());
958      break;
959    default:
960      NOTREACHED() << "Unexpected notification.";
961      return;
962  }
963}
964
965void TaskManagerExtensionProcessResourceProvider::AddToTaskManager(
966    ExtensionHost* extension_host) {
967  // Don't add dead extension processes.
968  if (!extension_host->IsRenderViewLive())
969    return;
970
971  TaskManagerExtensionProcessResource* resource =
972      new TaskManagerExtensionProcessResource(extension_host);
973  DCHECK(resources_.find(extension_host) == resources_.end());
974  resources_[extension_host] = resource;
975  pid_to_resources_[resource->process_id()] = resource;
976  task_manager_->AddResource(resource);
977}
978
979void TaskManagerExtensionProcessResourceProvider::RemoveFromTaskManager(
980    ExtensionHost* extension_host) {
981  if (!updating_)
982    return;
983  std::map<ExtensionHost*, TaskManagerExtensionProcessResource*>
984      ::iterator iter = resources_.find(extension_host);
985  if (iter == resources_.end())
986    return;
987
988  // Remove the resource from the Task Manager.
989  TaskManagerExtensionProcessResource* resource = iter->second;
990  task_manager_->RemoveResource(resource);
991
992  // Remove it from the provider.
993  resources_.erase(iter);
994
995  // Remove it from our pid map.
996  std::map<int, TaskManagerExtensionProcessResource*>::iterator pid_iter =
997      pid_to_resources_.find(resource->process_id());
998  DCHECK(pid_iter != pid_to_resources_.end());
999  if (pid_iter != pid_to_resources_.end())
1000    pid_to_resources_.erase(pid_iter);
1001
1002  // Finally, delete the resource.
1003  delete resource;
1004}
1005
1006////////////////////////////////////////////////////////////////////////////////
1007// TaskManagerNotificationResource class
1008////////////////////////////////////////////////////////////////////////////////
1009
1010SkBitmap* TaskManagerNotificationResource::default_icon_ = NULL;
1011
1012TaskManagerNotificationResource::TaskManagerNotificationResource(
1013    BalloonHost* balloon_host)
1014    : balloon_host_(balloon_host) {
1015  if (!default_icon_) {
1016    ResourceBundle& rb = ResourceBundle::GetSharedInstance();
1017    default_icon_ = rb.GetBitmapNamed(IDR_PLUGIN);
1018  }
1019  process_handle_ = balloon_host_->render_view_host()->process()->GetHandle();
1020  pid_ = base::GetProcId(process_handle_);
1021  title_ = UTF16ToWide(l10n_util::GetStringFUTF16(
1022      IDS_TASK_MANAGER_NOTIFICATION_PREFIX,
1023      balloon_host_->GetSource()));
1024}
1025
1026TaskManagerNotificationResource::~TaskManagerNotificationResource() {
1027}
1028
1029SkBitmap TaskManagerNotificationResource::GetIcon() const {
1030  return *default_icon_;
1031}
1032
1033base::ProcessHandle TaskManagerNotificationResource::GetProcess() const {
1034  return process_handle_;
1035}
1036
1037////////////////////////////////////////////////////////////////////////////////
1038// TaskManagerNotificationResourceProvider class
1039////////////////////////////////////////////////////////////////////////////////
1040
1041TaskManagerNotificationResourceProvider::
1042    TaskManagerNotificationResourceProvider(TaskManager* task_manager)
1043    : task_manager_(task_manager),
1044      updating_(false) {
1045}
1046
1047TaskManagerNotificationResourceProvider::
1048    ~TaskManagerNotificationResourceProvider() {
1049}
1050
1051TaskManager::Resource* TaskManagerNotificationResourceProvider::GetResource(
1052    int origin_pid,
1053    int render_process_host_id,
1054    int routing_id) {
1055  // TODO(johnnyg): provide resources by pid if necessary.
1056  return NULL;
1057}
1058
1059void TaskManagerNotificationResourceProvider::StartUpdating() {
1060  DCHECK(!updating_);
1061  updating_ = true;
1062
1063  // Add all the existing BalloonHosts.
1064  BalloonCollection* collection =
1065      g_browser_process->notification_ui_manager()->balloon_collection();
1066  const BalloonCollection::Balloons& balloons = collection->GetActiveBalloons();
1067  for (BalloonCollection::Balloons::const_iterator it = balloons.begin();
1068       it != balloons.end(); ++it) {
1069    AddToTaskManager((*it)->view()->GetHost());
1070  }
1071
1072  // Register for notifications about extension process changes.
1073  registrar_.Add(this, NotificationType::NOTIFY_BALLOON_CONNECTED,
1074                 NotificationService::AllSources());
1075  registrar_.Add(this, NotificationType::NOTIFY_BALLOON_DISCONNECTED,
1076                 NotificationService::AllSources());
1077}
1078
1079void TaskManagerNotificationResourceProvider::StopUpdating() {
1080  DCHECK(updating_);
1081  updating_ = false;
1082
1083  // Unregister for notifications about extension process changes.
1084  registrar_.Remove(this, NotificationType::NOTIFY_BALLOON_CONNECTED,
1085                    NotificationService::AllSources());
1086  registrar_.Remove(this, NotificationType::NOTIFY_BALLOON_DISCONNECTED,
1087                    NotificationService::AllSources());
1088
1089  // Delete all the resources.
1090  STLDeleteContainerPairSecondPointers(resources_.begin(), resources_.end());
1091  resources_.clear();
1092}
1093
1094void TaskManagerNotificationResourceProvider::Observe(
1095    NotificationType type,
1096    const NotificationSource& source,
1097    const NotificationDetails& details) {
1098  switch (type.value) {
1099    case NotificationType::NOTIFY_BALLOON_CONNECTED:
1100      AddToTaskManager(Source<BalloonHost>(source).ptr());
1101      break;
1102    case NotificationType::NOTIFY_BALLOON_DISCONNECTED:
1103      RemoveFromTaskManager(Source<BalloonHost>(source).ptr());
1104      break;
1105    default:
1106      NOTREACHED() << "Unexpected notification.";
1107      return;
1108  }
1109}
1110
1111void TaskManagerNotificationResourceProvider::AddToTaskManager(
1112    BalloonHost* balloon_host) {
1113  TaskManagerNotificationResource* resource =
1114      new TaskManagerNotificationResource(balloon_host);
1115  DCHECK(resources_.find(balloon_host) == resources_.end());
1116  resources_[balloon_host] = resource;
1117  task_manager_->AddResource(resource);
1118}
1119
1120void TaskManagerNotificationResourceProvider::RemoveFromTaskManager(
1121    BalloonHost* balloon_host) {
1122  if (!updating_)
1123    return;
1124  std::map<BalloonHost*, TaskManagerNotificationResource*>::iterator iter =
1125      resources_.find(balloon_host);
1126  if (iter == resources_.end())
1127    return;
1128
1129  // Remove the resource from the Task Manager.
1130  TaskManagerNotificationResource* resource = iter->second;
1131  task_manager_->RemoveResource(resource);
1132
1133  // Remove it from the map.
1134  resources_.erase(iter);
1135
1136  // Finally, delete the resource.
1137  delete resource;
1138}
1139
1140////////////////////////////////////////////////////////////////////////////////
1141// TaskManagerBrowserProcessResource class
1142////////////////////////////////////////////////////////////////////////////////
1143
1144SkBitmap* TaskManagerBrowserProcessResource::default_icon_ = NULL;
1145
1146TaskManagerBrowserProcessResource::TaskManagerBrowserProcessResource()
1147    : title_() {
1148  pid_ = base::GetCurrentProcId();
1149  bool success = base::OpenPrivilegedProcessHandle(pid_, &process_);
1150  DCHECK(success);
1151#if defined(OS_WIN)
1152  if (!default_icon_) {
1153    HICON icon = GetAppIcon();
1154    if (icon) {
1155      ICONINFO icon_info = {0};
1156      BITMAP bitmap_info = {0};
1157
1158      GetIconInfo(icon, &icon_info);
1159      GetObject(icon_info.hbmMask, sizeof(bitmap_info), &bitmap_info);
1160
1161      gfx::Size icon_size(bitmap_info.bmWidth, bitmap_info.bmHeight);
1162      default_icon_ = IconUtil::CreateSkBitmapFromHICON(icon, icon_size);
1163    }
1164  }
1165#elif defined(OS_LINUX)
1166  if (!default_icon_) {
1167    ResourceBundle& rb = ResourceBundle::GetSharedInstance();
1168    default_icon_ = rb.GetBitmapNamed(IDR_PRODUCT_LOGO_16);
1169  }
1170#elif defined(OS_MACOSX)
1171  if (!default_icon_) {
1172    // IDR_PRODUCT_LOGO_16 doesn't quite look like chrome/mac's icns icon. Load
1173    // the real app icon (requires a nsimage->skbitmap->nsimage conversion :-().
1174    default_icon_ = new SkBitmap(gfx::AppplicationIconAtSize(16));
1175  }
1176#else
1177  // TODO(port): Port icon code.
1178  NOTIMPLEMENTED();
1179#endif  // defined(OS_WIN)
1180}
1181
1182TaskManagerBrowserProcessResource::~TaskManagerBrowserProcessResource() {
1183  base::CloseProcessHandle(process_);
1184}
1185
1186// TaskManagerResource methods:
1187std::wstring TaskManagerBrowserProcessResource::GetTitle() const {
1188  if (title_.empty()) {
1189    title_ = l10n_util::GetString(IDS_TASK_MANAGER_WEB_BROWSER_CELL_TEXT);
1190  }
1191  return title_;
1192}
1193
1194SkBitmap TaskManagerBrowserProcessResource::GetIcon() const {
1195  return *default_icon_;
1196}
1197
1198size_t TaskManagerBrowserProcessResource::SqliteMemoryUsedBytes() const {
1199  return static_cast<size_t>(sqlite3_memory_used());
1200}
1201
1202base::ProcessHandle TaskManagerBrowserProcessResource::GetProcess() const {
1203  return base::GetCurrentProcessHandle();  // process_;
1204}
1205
1206////////////////////////////////////////////////////////////////////////////////
1207// TaskManagerBrowserProcessResourceProvider class
1208////////////////////////////////////////////////////////////////////////////////
1209
1210TaskManagerBrowserProcessResourceProvider::
1211    TaskManagerBrowserProcessResourceProvider(TaskManager* task_manager)
1212    : updating_(false),
1213      task_manager_(task_manager) {
1214}
1215
1216TaskManagerBrowserProcessResourceProvider::
1217    ~TaskManagerBrowserProcessResourceProvider() {
1218}
1219
1220TaskManager::Resource* TaskManagerBrowserProcessResourceProvider::GetResource(
1221    int origin_pid,
1222    int render_process_host_id,
1223    int routing_id) {
1224  if (origin_pid != resource_.process_id()) {
1225    return NULL;
1226  }
1227
1228  return &resource_;
1229}
1230
1231void TaskManagerBrowserProcessResourceProvider::StartUpdating() {
1232  task_manager_->AddResource(&resource_);
1233}
1234
1235void TaskManagerBrowserProcessResourceProvider::StopUpdating() {
1236}
1237