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