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