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