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
56namespace {
57
58// Returns the appropriate message prefix ID for tabs and extensions,
59// reflecting whether they are apps or in incognito mode.
60int 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////////////////////////////////////////////////////////////////////////////////
78TaskManagerRendererResource::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
96TaskManagerRendererResource::~TaskManagerRendererResource() {
97}
98
99void 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
110WebKit::WebCache::ResourceTypeStats
111TaskManagerRendererResource::GetWebCoreCacheStats() const {
112  return stats_;
113}
114
115size_t TaskManagerRendererResource::GetV8MemoryAllocated() const {
116  return v8_memory_allocated_;
117}
118
119size_t TaskManagerRendererResource::GetV8MemoryUsed() const {
120  return v8_memory_used_;
121}
122
123void TaskManagerRendererResource::NotifyResourceTypeStats(
124    const WebKit::WebCache::ResourceTypeStats& stats) {
125  stats_ = stats;
126  pending_stats_update_ = false;
127}
128
129void 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
136base::ProcessHandle TaskManagerRendererResource::GetProcess() const {
137  return process_;
138}
139
140TaskManager::Resource::Type TaskManagerRendererResource::GetType() const {
141  return RENDERER;
142}
143
144bool TaskManagerRendererResource::ReportsCacheStats() const {
145  return true;
146}
147
148bool TaskManagerRendererResource::ReportsV8MemoryStats() const {
149  return true;
150}
151
152bool TaskManagerRendererResource::SupportNetworkUsage() const {
153  return true;
154}
155
156////////////////////////////////////////////////////////////////////////////////
157// TaskManagerTabContentsResource class
158////////////////////////////////////////////////////////////////////////////////
159
160TaskManagerTabContentsResource::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
168TaskManagerTabContentsResource::~TaskManagerTabContentsResource() {
169}
170
171TaskManager::Resource::Type TaskManagerTabContentsResource::GetType() const {
172  return tab_contents_->tab_contents()->HostsExtension() ? EXTENSION : RENDERER;
173}
174
175string16 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
205SkBitmap TaskManagerTabContentsResource::GetIcon() const {
206  return tab_contents_->tab_contents()->GetFavicon();
207}
208
209TabContentsWrapper* TaskManagerTabContentsResource::GetTabContents() const {
210  return tab_contents_;
211}
212
213const 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
228TaskManagerTabContentsResourceProvider::
229    TaskManagerTabContentsResourceProvider(TaskManager* task_manager)
230    :  updating_(false),
231       task_manager_(task_manager) {
232}
233
234TaskManagerTabContentsResourceProvider::
235    ~TaskManagerTabContentsResourceProvider() {
236}
237
238TaskManager::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
264void 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
287void 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
307void 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
315void 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
338void 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
361void 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
397SkBitmap* TaskManagerPrerenderResource::default_icon_ = NULL;
398
399TaskManagerPrerenderResource::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
412TaskManagerPrerenderResource::~TaskManagerPrerenderResource() {
413}
414
415TaskManager::Resource::Type TaskManagerPrerenderResource::GetType() const {
416  return RENDERER;
417}
418
419string16 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
443SkBitmap 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
453TaskManagerPrerenderResourceProvider::TaskManagerPrerenderResourceProvider(
454    TaskManager* task_manager)
455    :  updating_(false),
456       task_manager_(task_manager) {
457}
458
459TaskManagerPrerenderResourceProvider::~TaskManagerPrerenderResourceProvider() {
460  STLDeleteContainerPairSecondPointers(resources_.begin(), resources_.end());
461}
462
463TaskManager::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
480void 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
506void 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
524void 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
536void 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
552void 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
580void 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
602SkBitmap* TaskManagerBackgroundContentsResource::default_icon_ = NULL;
603
604TaskManagerBackgroundContentsResource::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
623TaskManagerBackgroundContentsResource::~TaskManagerBackgroundContentsResource(
624    ) {
625}
626
627string16 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
640SkBitmap TaskManagerBackgroundContentsResource::GetIcon() const {
641  return *default_icon_;
642}
643
644bool TaskManagerBackgroundContentsResource::IsBackground() const {
645  return true;
646}
647
648////////////////////////////////////////////////////////////////////////////////
649// TaskManagerBackgroundContentsResourceProvider class
650////////////////////////////////////////////////////////////////////////////////
651
652TaskManagerBackgroundContentsResourceProvider::
653    TaskManagerBackgroundContentsResourceProvider(TaskManager* task_manager)
654    : updating_(false),
655      task_manager_(task_manager) {
656}
657
658TaskManagerBackgroundContentsResourceProvider::
659    ~TaskManagerBackgroundContentsResourceProvider() {
660}
661
662TaskManager::Resource*
663TaskManagerBackgroundContentsResourceProvider::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
688void 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
726void 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
744void 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
754void 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
768void 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
786void 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////////////////////////////////////////////////////////////////////////////////
842SkBitmap* TaskManagerChildProcessResource::default_icon_ = NULL;
843
844TaskManagerChildProcessResource::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
859TaskManagerChildProcessResource::~TaskManagerChildProcessResource() {
860}
861
862// TaskManagerResource methods:
863string16 TaskManagerChildProcessResource::GetTitle() const {
864  if (title_.empty())
865    title_ = GetLocalizedTitle();
866
867  return title_;
868}
869
870SkBitmap TaskManagerChildProcessResource::GetIcon() const {
871  return *default_icon_;
872}
873
874base::ProcessHandle TaskManagerChildProcessResource::GetProcess() const {
875  return child_process_.handle();
876}
877
878TaskManager::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
908bool TaskManagerChildProcessResource::SupportNetworkUsage() const {
909  return network_usage_support_;
910}
911
912void TaskManagerChildProcessResource::SetSupportNetworkUsage() {
913  network_usage_support_ = true;
914}
915
916string16 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
975TaskManagerChildProcessResourceProvider::
976    TaskManagerChildProcessResourceProvider(TaskManager* task_manager)
977    : updating_(false),
978      task_manager_(task_manager) {
979}
980
981TaskManagerChildProcessResourceProvider::
982    ~TaskManagerChildProcessResourceProvider() {
983}
984
985TaskManager::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
997void 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
1015void 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
1034void 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
1051void 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
1067void 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
1095void 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.
1105void 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.
1120void 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
1133SkBitmap* TaskManagerExtensionProcessResource::default_icon_ = NULL;
1134
1135TaskManagerExtensionProcessResource::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
1152TaskManagerExtensionProcessResource::~TaskManagerExtensionProcessResource() {
1153}
1154
1155string16 TaskManagerExtensionProcessResource::GetTitle() const {
1156  return title_;
1157}
1158
1159SkBitmap TaskManagerExtensionProcessResource::GetIcon() const {
1160  return *default_icon_;
1161}
1162
1163base::ProcessHandle TaskManagerExtensionProcessResource::GetProcess() const {
1164  return process_handle_;
1165}
1166
1167TaskManager::Resource::Type
1168TaskManagerExtensionProcessResource::GetType() const {
1169  return EXTENSION;
1170}
1171
1172bool TaskManagerExtensionProcessResource::SupportNetworkUsage() const {
1173  return true;
1174}
1175
1176void TaskManagerExtensionProcessResource::SetSupportNetworkUsage() {
1177  NOTREACHED();
1178}
1179
1180const Extension* TaskManagerExtensionProcessResource::GetExtension() const {
1181  return extension_host_->extension();
1182}
1183
1184bool TaskManagerExtensionProcessResource::IsBackground() const {
1185  return extension_host_->GetRenderViewType() ==
1186      ViewType::EXTENSION_BACKGROUND_PAGE;
1187}
1188
1189////////////////////////////////////////////////////////////////////////////////
1190// TaskManagerExtensionProcessResourceProvider class
1191////////////////////////////////////////////////////////////////////////////////
1192
1193TaskManagerExtensionProcessResourceProvider::
1194    TaskManagerExtensionProcessResourceProvider(TaskManager* task_manager)
1195    : task_manager_(task_manager),
1196      updating_(false) {
1197}
1198
1199TaskManagerExtensionProcessResourceProvider::
1200    ~TaskManagerExtensionProcessResourceProvider() {
1201}
1202
1203TaskManager::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
1215void 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
1253void 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
1272void 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
1290void 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
1304void 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
1335SkBitmap* TaskManagerNotificationResource::default_icon_ = NULL;
1336
1337TaskManagerNotificationResource::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
1350TaskManagerNotificationResource::~TaskManagerNotificationResource() {
1351}
1352
1353string16 TaskManagerNotificationResource::GetTitle() const {
1354  return title_;
1355}
1356
1357SkBitmap TaskManagerNotificationResource::GetIcon() const {
1358  return *default_icon_;
1359}
1360
1361base::ProcessHandle TaskManagerNotificationResource::GetProcess() const {
1362  return process_handle_;
1363}
1364
1365TaskManager::Resource::Type TaskManagerNotificationResource::GetType() const {
1366  return NOTIFICATION;
1367}
1368
1369bool TaskManagerNotificationResource::SupportNetworkUsage() const {
1370  return false;
1371}
1372
1373////////////////////////////////////////////////////////////////////////////////
1374// TaskManagerNotificationResourceProvider class
1375////////////////////////////////////////////////////////////////////////////////
1376
1377TaskManagerNotificationResourceProvider::
1378    TaskManagerNotificationResourceProvider(TaskManager* task_manager)
1379    : task_manager_(task_manager),
1380      updating_(false) {
1381}
1382
1383TaskManagerNotificationResourceProvider::
1384    ~TaskManagerNotificationResourceProvider() {
1385}
1386
1387TaskManager::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
1395void 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
1415void 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
1430void 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
1447void 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
1456void 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
1480SkBitmap* TaskManagerBrowserProcessResource::default_icon_ = NULL;
1481
1482TaskManagerBrowserProcessResource::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
1518TaskManagerBrowserProcessResource::~TaskManagerBrowserProcessResource() {
1519  base::CloseProcessHandle(process_);
1520}
1521
1522// TaskManagerResource methods:
1523string16 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
1530SkBitmap TaskManagerBrowserProcessResource::GetIcon() const {
1531  return *default_icon_;
1532}
1533
1534size_t TaskManagerBrowserProcessResource::SqliteMemoryUsedBytes() const {
1535  return static_cast<size_t>(sqlite3_memory_used());
1536}
1537
1538base::ProcessHandle TaskManagerBrowserProcessResource::GetProcess() const {
1539  return base::GetCurrentProcessHandle();  // process_;
1540}
1541
1542TaskManager::Resource::Type TaskManagerBrowserProcessResource::GetType() const {
1543  return BROWSER;
1544}
1545
1546bool TaskManagerBrowserProcessResource::SupportNetworkUsage() const {
1547  return true;
1548}
1549
1550void TaskManagerBrowserProcessResource::SetSupportNetworkUsage() {
1551  NOTREACHED();
1552}
1553
1554bool TaskManagerBrowserProcessResource::ReportsSqliteMemoryUsed() const {
1555  return true;
1556}
1557
1558////////////////////////////////////////////////////////////////////////////////
1559// TaskManagerBrowserProcessResourceProvider class
1560////////////////////////////////////////////////////////////////////////////////
1561
1562TaskManagerBrowserProcessResourceProvider::
1563    TaskManagerBrowserProcessResourceProvider(TaskManager* task_manager)
1564    : updating_(false),
1565      task_manager_(task_manager) {
1566}
1567
1568TaskManagerBrowserProcessResourceProvider::
1569    ~TaskManagerBrowserProcessResourceProvider() {
1570}
1571
1572TaskManager::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
1583void TaskManagerBrowserProcessResourceProvider::StartUpdating() {
1584  task_manager_->AddResource(&resource_);
1585}
1586
1587void TaskManagerBrowserProcessResourceProvider::StopUpdating() {
1588}
1589