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