task_manager.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
1// Copyright (c) 2012 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.h" 6 7#include "base/bind.h" 8#include "base/compiler_specific.h" 9#include "base/i18n/number_formatting.h" 10#include "base/i18n/rtl.h" 11#include "base/prefs/pref_registry_simple.h" 12#include "base/process_util.h" 13#include "base/rand_util.h" 14#include "base/stl_util.h" 15#include "base/stringprintf.h" 16#include "base/strings/string_number_conversions.h" 17#include "base/threading/thread.h" 18#include "base/utf_string_conversions.h" 19#include "chrome/browser/background/background_contents_service.h" 20#include "chrome/browser/background/background_contents_service_factory.h" 21#include "chrome/browser/browser_process.h" 22#include "chrome/browser/extensions/extension_host.h" 23#include "chrome/browser/extensions/extension_process_manager.h" 24#include "chrome/browser/extensions/extension_system.h" 25#include "chrome/browser/profiles/profile_manager.h" 26#include "chrome/browser/task_manager/task_manager_resource_providers.h" 27#include "chrome/browser/task_manager/task_manager_worker_resource_provider.h" 28#include "chrome/browser/ui/browser_finder.h" 29#include "chrome/browser/ui/browser_list.h" 30#include "chrome/browser/ui/browser_navigator.h" 31#include "chrome/common/pref_names.h" 32#include "chrome/common/url_constants.h" 33#include "chrome/common/view_type.h" 34#include "content/public/browser/browser_child_process_host.h" 35#include "content/public/browser/browser_thread.h" 36#include "content/public/browser/gpu_data_manager.h" 37#include "content/public/browser/gpu_data_manager_observer.h" 38#include "content/public/browser/render_view_host.h" 39#include "content/public/browser/resource_request_info.h" 40#include "content/public/browser/web_contents.h" 41#include "content/public/browser/web_contents_delegate.h" 42#include "content/public/common/result_codes.h" 43#include "grit/chromium_strings.h" 44#include "grit/generated_resources.h" 45#include "grit/ui_resources.h" 46#include "third_party/icu/public/i18n/unicode/coll.h" 47#include "ui/base/l10n/l10n_util.h" 48#include "ui/base/resource/resource_bundle.h" 49#include "ui/base/text/bytes_formatting.h" 50#include "ui/gfx/image/image_skia.h" 51 52#if defined(OS_WIN) 53#include "chrome/browser/task_manager/task_manager_os_resources_win.h" 54#endif 55 56using content::BrowserThread; 57using content::OpenURLParams; 58using content::Referrer; 59using content::ResourceRequestInfo; 60using content::WebContents; 61 62namespace { 63 64// The delay between updates of the information (in ms). 65#if defined(OS_MACOSX) 66// Match Activity Monitor's default refresh rate. 67const int kUpdateTimeMs = 2000; 68#else 69const int kUpdateTimeMs = 1000; 70#endif 71 72template <class T> 73int ValueCompare(T value1, T value2) { 74 if (value1 < value2) 75 return -1; 76 if (value1 == value2) 77 return 0; 78 return 1; 79} 80 81// Used when one or both of the results to compare are unavailable. 82int OrderUnavailableValue(bool v1, bool v2) { 83 if (!v1 && !v2) 84 return 0; 85 return v1 ? 1 : -1; 86} 87 88// Used by TaskManagerModel::CompareValues(). See it for details of return 89// value. 90template <class T> 91int ValueCompareMember(const TaskManagerModel* model, 92 bool (TaskManagerModel::*f)(int, T*) const, 93 int row1, 94 int row2) { 95 T value1; 96 T value2; 97 bool value1_valid = (model->*f)(row1, &value1); 98 bool value2_valid = (model->*f)(row2, &value2); 99 return value1_valid && value2_valid ? ValueCompare(value1, value2) : 100 OrderUnavailableValue(value1_valid, value2_valid); 101} 102 103string16 FormatStatsSize(const WebKit::WebCache::ResourceTypeStat& stat) { 104 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_CACHE_SIZE_CELL_TEXT, 105 ui::FormatBytesWithUnits(stat.size, ui::DATA_UNITS_KIBIBYTE, false), 106 ui::FormatBytesWithUnits(stat.liveSize, ui::DATA_UNITS_KIBIBYTE, false)); 107} 108 109// Returns true if the specified id should use the first value in the group. 110bool IsSharedByGroup(int col_id) { 111 switch (col_id) { 112 case IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN: 113 case IDS_TASK_MANAGER_SHARED_MEM_COLUMN: 114 case IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN: 115 case IDS_TASK_MANAGER_CPU_COLUMN: 116 case IDS_TASK_MANAGER_PROCESS_ID_COLUMN: 117 case IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN: 118 case IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN: 119 case IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN: 120 case IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN: 121 case IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN: 122 return true; 123 default: 124 return false; 125 } 126} 127 128} // namespace 129 130class TaskManagerModelGpuDataManagerObserver 131 : public content::GpuDataManagerObserver { 132 public: 133 TaskManagerModelGpuDataManagerObserver() { 134 content::GpuDataManager::GetInstance()->AddObserver(this); 135 } 136 137 virtual ~TaskManagerModelGpuDataManagerObserver() { 138 content::GpuDataManager::GetInstance()->RemoveObserver(this); 139 } 140 141 static void NotifyVideoMemoryUsageStats( 142 content::GPUVideoMemoryUsageStats video_memory_usage_stats) { 143 TaskManager::GetInstance()->model()->NotifyVideoMemoryUsageStats( 144 video_memory_usage_stats); 145 } 146 147 virtual void OnVideoMemoryUsageStatsUpdate( 148 const content::GPUVideoMemoryUsageStats& video_memory_usage_stats) 149 OVERRIDE { 150 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) { 151 NotifyVideoMemoryUsageStats(video_memory_usage_stats); 152 } else { 153 BrowserThread::PostTask( 154 BrowserThread::UI, FROM_HERE, base::Bind( 155 &TaskManagerModelGpuDataManagerObserver:: 156 NotifyVideoMemoryUsageStats, 157 video_memory_usage_stats)); 158 } 159 } 160}; 161 162TaskManagerModel::PerResourceValues::PerResourceValues() 163 : is_title_valid(false), 164 is_profile_name_valid(false), 165 network_usage(0), 166 is_process_id_valid(false), 167 process_id(0), 168 is_goats_teleported_valid(false), 169 goats_teleported(0), 170 is_webcore_stats_valid(false), 171 is_fps_valid(false), 172 fps(0), 173 is_sqlite_memory_bytes_valid(false), 174 sqlite_memory_bytes(0), 175 is_v8_memory_valid(false), 176 v8_memory_allocated(0), 177 v8_memory_used(0) { 178} 179 180TaskManagerModel::PerResourceValues::~PerResourceValues() { 181} 182 183TaskManagerModel::PerProcessValues::PerProcessValues() 184 : is_cpu_usage_valid(false), 185 cpu_usage(0), 186 is_private_and_shared_valid(false), 187 private_bytes(0), 188 shared_bytes(0), 189 is_physical_memory_valid(false), 190 physical_memory(0), 191 is_video_memory_valid(false), 192 video_memory(0), 193 video_memory_has_duplicates(false), 194 is_gdi_handles_valid(false), 195 gdi_handles(0), 196 gdi_handles_peak(0), 197 is_user_handles_valid(0), 198 user_handles(0), 199 user_handles_peak(0) { 200} 201 202TaskManagerModel::PerProcessValues::~PerProcessValues() { 203} 204 205//////////////////////////////////////////////////////////////////////////////// 206// TaskManagerModel class 207//////////////////////////////////////////////////////////////////////////////// 208 209TaskManagerModel::TaskManagerModel(TaskManager* task_manager) 210 : pending_video_memory_usage_stats_update_(false), 211 update_requests_(0), 212 listen_requests_(0), 213 update_state_(IDLE), 214 goat_salt_(base::RandUint64()), 215 last_unique_id_(0) { 216 AddResourceProvider( 217 new TaskManagerBrowserProcessResourceProvider(task_manager)); 218 AddResourceProvider( 219 new TaskManagerBackgroundContentsResourceProvider(task_manager)); 220 AddResourceProvider(new TaskManagerTabContentsResourceProvider(task_manager)); 221 AddResourceProvider(new TaskManagerPanelResourceProvider(task_manager)); 222 AddResourceProvider( 223 new TaskManagerChildProcessResourceProvider(task_manager)); 224 AddResourceProvider( 225 new TaskManagerExtensionProcessResourceProvider(task_manager)); 226 AddResourceProvider( 227 new TaskManagerGuestResourceProvider(task_manager)); 228 229#if defined(ENABLE_NOTIFICATIONS) 230 TaskManager::ResourceProvider* provider = 231 TaskManagerNotificationResourceProvider::Create(task_manager); 232 if (provider) 233 AddResourceProvider(provider); 234#endif 235 236 AddResourceProvider(new TaskManagerWorkerResourceProvider(task_manager)); 237} 238 239void TaskManagerModel::AddObserver(TaskManagerModelObserver* observer) { 240 observer_list_.AddObserver(observer); 241} 242 243void TaskManagerModel::RemoveObserver(TaskManagerModelObserver* observer) { 244 observer_list_.RemoveObserver(observer); 245} 246 247int TaskManagerModel::ResourceCount() const { 248 return resources_.size(); 249} 250 251int TaskManagerModel::GroupCount() const { 252 return group_map_.size(); 253} 254 255int64 TaskManagerModel::GetNetworkUsage(int index) const { 256 return GetNetworkUsage(GetResource(index)); 257} 258 259double TaskManagerModel::GetCPUUsage(int index) const { 260 return GetCPUUsage(GetResource(index)); 261} 262 263base::ProcessId TaskManagerModel::GetProcessId(int index) const { 264 PerResourceValues& values(GetPerResourceValues(index)); 265 if (!values.is_process_id_valid) { 266 values.is_process_id_valid = true; 267 values.process_id = base::GetProcId(GetResource(index)->GetProcess()); 268 } 269 return values.process_id; 270} 271 272base::ProcessHandle TaskManagerModel::GetProcess(int index) const { 273 return GetResource(index)->GetProcess(); 274} 275 276int TaskManagerModel::GetResourceUniqueId(int index) const { 277 return GetResource(index)->get_unique_id(); 278} 279 280int TaskManagerModel::GetResourceIndexByUniqueId(const int unique_id) const { 281 for (int resource_index = 0; resource_index < ResourceCount(); 282 ++resource_index) { 283 if (GetResourceUniqueId(resource_index) == unique_id) 284 return resource_index; 285 } 286 return -1; 287} 288 289string16 TaskManagerModel::GetResourceById(int index, int col_id) const { 290 if (IsSharedByGroup(col_id) && !IsResourceFirstInGroup(index)) 291 return string16(); 292 293 switch (col_id) { 294 case IDS_TASK_MANAGER_TASK_COLUMN: 295 return GetResourceTitle(index); 296 297 case IDS_TASK_MANAGER_PROFILE_NAME_COLUMN: 298 return GetResourceProfileName(index); 299 300 case IDS_TASK_MANAGER_NET_COLUMN: 301 return GetResourceNetworkUsage(index); 302 303 case IDS_TASK_MANAGER_CPU_COLUMN: 304 return GetResourceCPUUsage(index); 305 306 case IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN: 307 return GetResourcePrivateMemory(index); 308 309 case IDS_TASK_MANAGER_SHARED_MEM_COLUMN: 310 return GetResourceSharedMemory(index); 311 312 case IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN: 313 return GetResourcePhysicalMemory(index); 314 315 case IDS_TASK_MANAGER_PROCESS_ID_COLUMN: 316 return GetResourceProcessId(index); 317 318 case IDS_TASK_MANAGER_GDI_HANDLES_COLUMN: 319 return GetResourceGDIHandles(index); 320 321 case IDS_TASK_MANAGER_USER_HANDLES_COLUMN: 322 return GetResourceUSERHandles(index); 323 324 case IDS_TASK_MANAGER_GOATS_TELEPORTED_COLUMN: 325 return GetResourceGoatsTeleported(index); 326 327 case IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN: 328 return GetResourceWebCoreImageCacheSize(index); 329 330 case IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN: 331 return GetResourceWebCoreScriptsCacheSize(index); 332 333 case IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN: 334 return GetResourceWebCoreCSSCacheSize(index); 335 336 case IDS_TASK_MANAGER_FPS_COLUMN: 337 return GetResourceFPS(index); 338 339 case IDS_TASK_MANAGER_VIDEO_MEMORY_COLUMN: 340 return GetResourceVideoMemory(index); 341 342 case IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN: 343 return GetResourceSqliteMemoryUsed(index); 344 345 case IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN: 346 return GetResourceV8MemoryAllocatedSize(index); 347 348 default: 349 NOTREACHED(); 350 return string16(); 351 } 352} 353 354const string16& TaskManagerModel::GetResourceTitle(int index) const { 355 PerResourceValues& values = GetPerResourceValues(index); 356 if (!values.is_title_valid) { 357 values.is_title_valid = true; 358 values.title = GetResource(index)->GetTitle(); 359 } 360 return values.title; 361} 362 363const string16& TaskManagerModel::GetResourceProfileName(int index) const { 364 PerResourceValues& values(GetPerResourceValues(index)); 365 if (!values.is_profile_name_valid) { 366 values.is_profile_name_valid = true; 367 values.profile_name = GetResource(index)->GetProfileName(); 368 } 369 return values.profile_name; 370} 371 372string16 TaskManagerModel::GetResourceNetworkUsage(int index) const { 373 int64 net_usage = GetNetworkUsage(index); 374 if (net_usage == -1) 375 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT); 376 if (net_usage == 0) 377 return ASCIIToUTF16("0"); 378 string16 net_byte = ui::FormatSpeed(net_usage); 379 // Force number string to have LTR directionality. 380 return base::i18n::GetDisplayStringInLTRDirectionality(net_byte); 381} 382 383string16 TaskManagerModel::GetResourceCPUUsage(int index) const { 384 return UTF8ToUTF16(base::StringPrintf( 385#if defined(OS_MACOSX) 386 // Activity Monitor shows %cpu with one decimal digit -- be 387 // consistent with that. 388 "%.1f", 389#else 390 "%.0f", 391#endif 392 GetCPUUsage(GetResource(index)))); 393} 394 395string16 TaskManagerModel::GetResourcePrivateMemory(int index) const { 396 size_t private_mem; 397 if (!GetPrivateMemory(index, &private_mem)) 398 return ASCIIToUTF16("N/A"); 399 return GetMemCellText(private_mem); 400} 401 402string16 TaskManagerModel::GetResourceSharedMemory(int index) const { 403 size_t shared_mem; 404 if (!GetSharedMemory(index, &shared_mem)) 405 return ASCIIToUTF16("N/A"); 406 return GetMemCellText(shared_mem); 407} 408 409string16 TaskManagerModel::GetResourcePhysicalMemory(int index) const { 410 size_t phys_mem; 411 GetPhysicalMemory(index, &phys_mem); 412 return GetMemCellText(phys_mem); 413} 414 415string16 TaskManagerModel::GetResourceProcessId(int index) const { 416 return base::IntToString16(GetProcessId(index)); 417} 418 419string16 TaskManagerModel::GetResourceGDIHandles(int index) const { 420 size_t current, peak; 421 GetGDIHandles(index, ¤t, &peak); 422 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_HANDLES_CELL_TEXT, 423 base::IntToString16(current), base::IntToString16(peak)); 424} 425 426string16 TaskManagerModel::GetResourceUSERHandles(int index) const { 427 size_t current, peak; 428 GetUSERHandles(index, ¤t, &peak); 429 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_HANDLES_CELL_TEXT, 430 base::IntToString16(current), base::IntToString16(peak)); 431} 432 433string16 TaskManagerModel::GetResourceWebCoreImageCacheSize( 434 int index) const { 435 if (!CacheWebCoreStats(index)) 436 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT); 437 return FormatStatsSize(GetPerResourceValues(index).webcore_stats.images); 438} 439 440string16 TaskManagerModel::GetResourceWebCoreScriptsCacheSize( 441 int index) const { 442 if (!CacheWebCoreStats(index)) 443 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT); 444 return FormatStatsSize(GetPerResourceValues(index).webcore_stats.scripts); 445} 446 447string16 TaskManagerModel::GetResourceWebCoreCSSCacheSize( 448 int index) const { 449 if (!CacheWebCoreStats(index)) 450 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT); 451 return FormatStatsSize( 452 GetPerResourceValues(index).webcore_stats.cssStyleSheets); 453} 454 455string16 TaskManagerModel::GetResourceVideoMemory(int index) const { 456 size_t video_memory; 457 bool has_duplicates; 458 if (!GetVideoMemory(index, &video_memory, &has_duplicates) || !video_memory) 459 return ASCIIToUTF16("N/A"); 460 if (has_duplicates) { 461 return ASCIIToUTF16("(") + 462 GetMemCellText(video_memory) + 463 ASCIIToUTF16(")"); 464 } 465 return GetMemCellText(video_memory); 466} 467 468string16 TaskManagerModel::GetResourceFPS( 469 int index) const { 470 float fps = 0; 471 if (!GetFPS(index, &fps)) 472 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT); 473 return UTF8ToUTF16(base::StringPrintf("%.0f", fps)); 474} 475 476string16 TaskManagerModel::GetResourceSqliteMemoryUsed(int index) const { 477 size_t bytes = 0; 478 if (!GetSqliteMemoryUsedBytes(index, &bytes)) 479 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT); 480 return GetMemCellText(bytes); 481} 482 483string16 TaskManagerModel::GetResourceGoatsTeleported(int index) const { 484 CHECK_LT(index, ResourceCount()); 485 return base::FormatNumber(GetGoatsTeleported(index)); 486} 487 488string16 TaskManagerModel::GetResourceV8MemoryAllocatedSize( 489 int index) const { 490 size_t memory_allocated = 0, memory_used = 0; 491 if (!GetV8MemoryUsed(index, &memory_used) || 492 !GetV8Memory(index, &memory_allocated)) 493 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT); 494 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_CACHE_SIZE_CELL_TEXT, 495 ui::FormatBytesWithUnits(memory_allocated, 496 ui::DATA_UNITS_KIBIBYTE, 497 false), 498 ui::FormatBytesWithUnits(memory_used, 499 ui::DATA_UNITS_KIBIBYTE, 500 false)); 501} 502 503bool TaskManagerModel::GetPrivateMemory(int index, size_t* result) const { 504 *result = 0; 505 base::ProcessHandle handle = GetResource(index)->GetProcess(); 506 if (!CachePrivateAndSharedMemory(handle)) 507 return false; 508 *result = per_process_cache_[handle].private_bytes; 509 return true; 510} 511 512bool TaskManagerModel::GetSharedMemory(int index, size_t* result) const { 513 *result = 0; 514 base::ProcessHandle handle = GetResource(index)->GetProcess(); 515 if (!CachePrivateAndSharedMemory(handle)) 516 return false; 517 *result = per_process_cache_[handle].shared_bytes; 518 return true; 519} 520 521bool TaskManagerModel::GetPhysicalMemory(int index, size_t* result) const { 522 *result = 0; 523 524 base::ProcessHandle handle = GetResource(index)->GetProcess(); 525 PerProcessValues& values(per_process_cache_[handle]); 526 527 if (!values.is_physical_memory_valid) { 528 base::WorkingSetKBytes ws_usage; 529 MetricsMap::const_iterator iter = metrics_map_.find(handle); 530 if (iter == metrics_map_.end() || 531 !iter->second->GetWorkingSetKBytes(&ws_usage)) 532 return false; 533 534 // Memory = working_set.private + working_set.shareable. 535 // We exclude the shared memory. 536 values.is_physical_memory_valid = true; 537 values.physical_memory = iter->second->GetWorkingSetSize(); 538 values.physical_memory -= ws_usage.shared * 1024; 539 } 540 *result = values.physical_memory; 541 return true; 542} 543 544void TaskManagerModel::GetGDIHandles(int index, 545 size_t* current, 546 size_t* peak) const { 547 *current = 0; 548 *peak = 0; 549#if defined(OS_WIN) 550 base::ProcessHandle handle = GetResource(index)->GetProcess(); 551 PerProcessValues& values(per_process_cache_[handle]); 552 553 if (!values.is_gdi_handles_valid) { 554 GetWinGDIHandles(GetResource(index)->GetProcess(), 555 &values.gdi_handles, 556 &values.gdi_handles_peak); 557 values.is_gdi_handles_valid = true; 558 } 559 *current = values.gdi_handles; 560 *peak = values.gdi_handles_peak; 561#endif 562} 563 564void TaskManagerModel::GetUSERHandles(int index, 565 size_t* current, 566 size_t* peak) const { 567 *current = 0; 568 *peak = 0; 569#if defined(OS_WIN) 570 base::ProcessHandle handle = GetResource(index)->GetProcess(); 571 PerProcessValues& values(per_process_cache_[handle]); 572 573 if (!values.is_user_handles_valid) { 574 GetWinUSERHandles(GetResource(index)->GetProcess(), 575 &values.user_handles, 576 &values.user_handles_peak); 577 values.is_user_handles_valid = true; 578 } 579 *current = values.user_handles; 580 *peak = values.user_handles_peak; 581#endif 582} 583 584bool TaskManagerModel::GetWebCoreCacheStats( 585 int index, 586 WebKit::WebCache::ResourceTypeStats* result) const { 587 if (!CacheWebCoreStats(index)) 588 return false; 589 *result = GetPerResourceValues(index).webcore_stats; 590 return true; 591} 592 593bool TaskManagerModel::GetVideoMemory(int index, 594 size_t* video_memory, 595 bool* has_duplicates) const { 596 *video_memory = 0; 597 *has_duplicates = false; 598 599 base::ProcessId pid = GetProcessId(index); 600 PerProcessValues& values( 601 per_process_cache_[GetResource(index)->GetProcess()]); 602 if (!values.is_video_memory_valid) { 603 content::GPUVideoMemoryUsageStats::ProcessMap::const_iterator i = 604 video_memory_usage_stats_.process_map.find(pid); 605 if (i == video_memory_usage_stats_.process_map.end()) 606 return false; 607 values.is_video_memory_valid = true; 608 values.video_memory = i->second.video_memory; 609 values.video_memory_has_duplicates = i->second.has_duplicates; 610 } 611 *video_memory = values.video_memory; 612 *has_duplicates = values.video_memory_has_duplicates; 613 return true; 614} 615 616bool TaskManagerModel::GetFPS(int index, float* result) const { 617 *result = 0; 618 PerResourceValues& values(GetPerResourceValues(index)); 619 if (!values.is_fps_valid) { 620 if (!GetResource(index)->ReportsFPS()) 621 return false; 622 values.is_fps_valid = true; 623 values.fps = GetResource(index)->GetFPS(); 624 } 625 *result = values.fps; 626 return true; 627} 628 629bool TaskManagerModel::GetSqliteMemoryUsedBytes( 630 int index, 631 size_t* result) const { 632 *result = 0; 633 PerResourceValues& values(GetPerResourceValues(index)); 634 if (!values.is_sqlite_memory_bytes_valid) { 635 if (!GetResource(index)->ReportsSqliteMemoryUsed()) 636 return false; 637 values.is_sqlite_memory_bytes_valid = true; 638 values.sqlite_memory_bytes = GetResource(index)->SqliteMemoryUsedBytes(); 639 } 640 *result = values.sqlite_memory_bytes; 641 return true; 642} 643 644bool TaskManagerModel::GetV8Memory(int index, size_t* result) const { 645 *result = 0; 646 if (!CacheV8Memory(index)) 647 return false; 648 *result = GetPerResourceValues(index).v8_memory_allocated; 649 return true; 650} 651 652bool TaskManagerModel::GetV8MemoryUsed(int index, size_t* result) const { 653 *result = 0; 654 if (!CacheV8Memory(index)) 655 return false; 656 *result = GetPerResourceValues(index).v8_memory_used; 657 return true; 658} 659 660bool TaskManagerModel::CanActivate(int index) const { 661 CHECK_LT(index, ResourceCount()); 662 return GetResourceWebContents(index) != NULL; 663} 664 665bool TaskManagerModel::CanInspect(int index) const { 666 return GetResource(index)->CanInspect(); 667} 668 669void TaskManagerModel::Inspect(int index) const { 670 CHECK_LT(index, ResourceCount()); 671 GetResource(index)->Inspect(); 672} 673 674int TaskManagerModel::GetGoatsTeleported(int index) const { 675 PerResourceValues& values(GetPerResourceValues(index)); 676 if (!values.is_goats_teleported_valid) { 677 values.is_goats_teleported_valid = true; 678 values.goats_teleported = goat_salt_ * (index + 1); 679 values.goats_teleported = (values.goats_teleported >> 16) & 255; 680 } 681 return values.goats_teleported; 682} 683 684bool TaskManagerModel::IsResourceFirstInGroup(int index) const { 685 TaskManager::Resource* resource = GetResource(index); 686 GroupMap::const_iterator iter = group_map_.find(resource->GetProcess()); 687 DCHECK(iter != group_map_.end()); 688 const ResourceList* group = iter->second; 689 return ((*group)[0] == resource); 690} 691 692bool TaskManagerModel::IsResourceLastInGroup(int index) const { 693 TaskManager::Resource* resource = GetResource(index); 694 GroupMap::const_iterator iter = group_map_.find(resource->GetProcess()); 695 DCHECK(iter != group_map_.end()); 696 const ResourceList* group = iter->second; 697 return (group->back() == resource); 698} 699 700bool TaskManagerModel::IsBackgroundResource(int index) const { 701 return GetResource(index)->IsBackground(); 702} 703 704gfx::ImageSkia TaskManagerModel::GetResourceIcon(int index) const { 705 gfx::ImageSkia icon = GetResource(index)->GetIcon(); 706 if (!icon.isNull()) 707 return icon; 708 709 static gfx::ImageSkia* default_icon = ResourceBundle::GetSharedInstance(). 710 GetImageSkiaNamed(IDR_DEFAULT_FAVICON); 711 return *default_icon; 712} 713 714TaskManagerModel::GroupRange 715TaskManagerModel::GetGroupRangeForResource(int index) const { 716 TaskManager::Resource* resource = GetResource(index); 717 GroupMap::const_iterator group_iter = 718 group_map_.find(resource->GetProcess()); 719 DCHECK(group_iter != group_map_.end()); 720 ResourceList* group = group_iter->second; 721 DCHECK(group); 722 if (group->size() == 1) { 723 return std::make_pair(index, 1); 724 } else { 725 for (int i = index; i >= 0; --i) { 726 if (GetResource(i) == (*group)[0]) 727 return std::make_pair(i, group->size()); 728 } 729 NOTREACHED(); 730 return std::make_pair(-1, -1); 731 } 732} 733 734int TaskManagerModel::GetGroupIndexForResource(int index) const { 735 int group_index = -1; 736 for (int i = 0; i <= index; ++i) { 737 if (IsResourceFirstInGroup(i)) 738 group_index++; 739 } 740 741 DCHECK_NE(group_index, -1); 742 return group_index; 743} 744 745int TaskManagerModel::GetResourceIndexForGroup(int group_index, 746 int index_in_group) const { 747 int group_count = -1; 748 int count_in_group = -1; 749 for (int i = 0; i < ResourceCount(); ++i) { 750 if (IsResourceFirstInGroup(i)) 751 group_count++; 752 753 if (group_count == group_index) { 754 count_in_group++; 755 if (count_in_group == index_in_group) 756 return i; 757 } else if (group_count > group_index) { 758 break; 759 } 760 } 761 762 NOTREACHED(); 763 return -1; 764} 765 766int TaskManagerModel::CompareValues(int row1, int row2, int col_id) const { 767 CHECK(row1 < ResourceCount() && row2 < ResourceCount()); 768 switch (col_id) { 769 case IDS_TASK_MANAGER_TASK_COLUMN: { 770 static icu::Collator* collator = NULL; 771 if (!collator) { 772 UErrorCode create_status = U_ZERO_ERROR; 773 collator = icu::Collator::createInstance(create_status); 774 if (!U_SUCCESS(create_status)) { 775 collator = NULL; 776 NOTREACHED(); 777 } 778 } 779 const string16& title1 = GetResourceTitle(row1); 780 const string16& title2 = GetResourceTitle(row2); 781 UErrorCode compare_status = U_ZERO_ERROR; 782 UCollationResult compare_result = collator->compare( 783 static_cast<const UChar*>(title1.c_str()), 784 static_cast<int>(title1.length()), 785 static_cast<const UChar*>(title2.c_str()), 786 static_cast<int>(title2.length()), 787 compare_status); 788 DCHECK(U_SUCCESS(compare_status)); 789 return compare_result; 790 } 791 792 case IDS_TASK_MANAGER_PROFILE_NAME_COLUMN: { 793 const string16& profile1 = GetResourceProfileName(row1); 794 const string16& profile2 = GetResourceProfileName(row2); 795 return profile1.compare(0, profile1.length(), profile2, 0, 796 profile2.length()); 797 } 798 799 case IDS_TASK_MANAGER_NET_COLUMN: 800 return ValueCompare(GetNetworkUsage(GetResource(row1)), 801 GetNetworkUsage(GetResource(row2))); 802 803 case IDS_TASK_MANAGER_CPU_COLUMN: 804 return ValueCompare(GetCPUUsage(GetResource(row1)), 805 GetCPUUsage(GetResource(row2))); 806 807 case IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN: 808 return ValueCompareMember( 809 this, &TaskManagerModel::GetPrivateMemory, row1, row2); 810 811 case IDS_TASK_MANAGER_SHARED_MEM_COLUMN: 812 return ValueCompareMember( 813 this, &TaskManagerModel::GetSharedMemory, row1, row2); 814 815 case IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN: 816 return ValueCompareMember( 817 this, &TaskManagerModel::GetPhysicalMemory, row1, row2); 818 819 case IDS_TASK_MANAGER_PROCESS_ID_COLUMN: 820 return ValueCompare(GetProcessId(row1), GetProcessId(row2)); 821 822 case IDS_TASK_MANAGER_GDI_HANDLES_COLUMN: { 823 size_t current1, peak1; 824 size_t current2, peak2; 825 GetGDIHandles(row1, ¤t1, &peak1); 826 GetGDIHandles(row2, ¤t2, &peak2); 827 return ValueCompare(current1, current2); 828 } 829 830 case IDS_TASK_MANAGER_USER_HANDLES_COLUMN: { 831 size_t current1, peak1; 832 size_t current2, peak2; 833 GetUSERHandles(row1, ¤t1, &peak1); 834 GetUSERHandles(row2, ¤t2, &peak2); 835 return ValueCompare(current1, current2); 836 } 837 838 case IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN: 839 case IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN: 840 case IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN: { 841 bool row1_stats_valid = CacheWebCoreStats(row1); 842 bool row2_stats_valid = CacheWebCoreStats(row2); 843 if (row1_stats_valid && row2_stats_valid) { 844 const WebKit::WebCache::ResourceTypeStats& stats1( 845 GetPerResourceValues(row1).webcore_stats); 846 const WebKit::WebCache::ResourceTypeStats& stats2( 847 GetPerResourceValues(row2).webcore_stats); 848 switch (col_id) { 849 case IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN: 850 return ValueCompare(stats1.images.size, stats2.images.size); 851 case IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN: 852 return ValueCompare(stats1.scripts.size, stats2.scripts.size); 853 case IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN: 854 return ValueCompare(stats1.cssStyleSheets.size, 855 stats2.cssStyleSheets.size); 856 default: 857 NOTREACHED(); 858 return 0; 859 } 860 } 861 return OrderUnavailableValue(row1_stats_valid, row2_stats_valid); 862 } 863 864 case IDS_TASK_MANAGER_FPS_COLUMN: 865 return ValueCompareMember( 866 this, &TaskManagerModel::GetFPS, row1, row2); 867 868 case IDS_TASK_MANAGER_VIDEO_MEMORY_COLUMN: { 869 size_t value1; 870 size_t value2; 871 bool has_duplicates; 872 bool value1_valid = GetVideoMemory(row1, &value1, &has_duplicates); 873 bool value2_valid = GetVideoMemory(row2, &value2, &has_duplicates); 874 return value1_valid && value2_valid ? ValueCompare(value1, value2) : 875 OrderUnavailableValue(value1_valid, value2_valid); 876 } 877 878 case IDS_TASK_MANAGER_GOATS_TELEPORTED_COLUMN: 879 return ValueCompare(GetGoatsTeleported(row1), GetGoatsTeleported(row2)); 880 881 case IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN: 882 return ValueCompareMember( 883 this, &TaskManagerModel::GetV8Memory, row1, row2); 884 885 case IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN: 886 return ValueCompareMember( 887 this, &TaskManagerModel::GetSqliteMemoryUsedBytes, row1, row2); 888 889 default: 890 NOTREACHED(); 891 break; 892 } 893 return 0; 894} 895 896int TaskManagerModel::GetUniqueChildProcessId(int index) const { 897 return GetResource(index)->GetUniqueChildProcessId(); 898} 899 900TaskManager::Resource::Type TaskManagerModel::GetResourceType(int index) const { 901 return GetResource(index)->GetType(); 902} 903 904WebContents* TaskManagerModel::GetResourceWebContents(int index) const { 905 return GetResource(index)->GetWebContents(); 906} 907 908const extensions::Extension* TaskManagerModel::GetResourceExtension( 909 int index) const { 910 return GetResource(index)->GetExtension(); 911} 912 913void TaskManagerModel::AddResource(TaskManager::Resource* resource) { 914 resource->unique_id_ = ++last_unique_id_; 915 916 base::ProcessHandle process = resource->GetProcess(); 917 918 ResourceList* group_entries = NULL; 919 GroupMap::const_iterator group_iter = group_map_.find(process); 920 int new_entry_index = 0; 921 if (group_iter == group_map_.end()) { 922 group_entries = new ResourceList(); 923 group_map_[process] = group_entries; 924 group_entries->push_back(resource); 925 926 // Not part of a group, just put at the end of the list. 927 resources_.push_back(resource); 928 new_entry_index = static_cast<int>(resources_.size() - 1); 929 } else { 930 group_entries = group_iter->second; 931 group_entries->push_back(resource); 932 933 // Insert the new entry right after the last entry of its group. 934 ResourceList::iterator iter = 935 std::find(resources_.begin(), 936 resources_.end(), 937 (*group_entries)[group_entries->size() - 2]); 938 DCHECK(iter != resources_.end()); 939 new_entry_index = static_cast<int>(iter - resources_.begin()) + 1; 940 resources_.insert(++iter, resource); 941 } 942 943 // Create the ProcessMetrics for this process if needed (not in map). 944 if (metrics_map_.find(process) == metrics_map_.end()) { 945 base::ProcessMetrics* pm = 946#if !defined(OS_MACOSX) 947 base::ProcessMetrics::CreateProcessMetrics(process); 948#else 949 base::ProcessMetrics::CreateProcessMetrics( 950 process, content::BrowserChildProcessHost::GetPortProvider()); 951#endif 952 953 metrics_map_[process] = pm; 954 } 955 956 // Notify the table that the contents have changed for it to redraw. 957 FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_, 958 OnItemsAdded(new_entry_index, 1)); 959} 960 961void TaskManagerModel::RemoveResource(TaskManager::Resource* resource) { 962 base::ProcessHandle process = resource->GetProcess(); 963 964 // Find the associated group. 965 GroupMap::iterator group_iter = group_map_.find(process); 966 DCHECK(group_iter != group_map_.end()); 967 ResourceList* group_entries = group_iter->second; 968 969 // Remove the entry from the group map. 970 ResourceList::iterator iter = std::find(group_entries->begin(), 971 group_entries->end(), 972 resource); 973 DCHECK(iter != group_entries->end()); 974 group_entries->erase(iter); 975 976 // If there are no more entries for that process, do the clean-up. 977 if (group_entries->empty()) { 978 delete group_entries; 979 group_map_.erase(process); 980 981 // Nobody is using this process, we don't need the process metrics anymore. 982 MetricsMap::iterator pm_iter = metrics_map_.find(process); 983 DCHECK(pm_iter != metrics_map_.end()); 984 if (pm_iter != metrics_map_.end()) { 985 delete pm_iter->second; 986 metrics_map_.erase(process); 987 } 988 } 989 990 // Prepare to remove the entry from the model list. 991 iter = std::find(resources_.begin(), resources_.end(), resource); 992 DCHECK(iter != resources_.end()); 993 int index = static_cast<int>(iter - resources_.begin()); 994 995 // Notify the observers that the contents will change. 996 FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_, 997 OnItemsToBeRemoved(index, 1)); 998 999 // Now actually remove the entry from the model list. 1000 resources_.erase(iter); 1001 1002 // Remove the entry from the network maps. 1003 ResourceValueMap::iterator net_iter = 1004 current_byte_count_map_.find(resource); 1005 if (net_iter != current_byte_count_map_.end()) 1006 current_byte_count_map_.erase(net_iter); 1007 1008 // Notify the table that the contents have changed. 1009 FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_, 1010 OnItemsRemoved(index, 1)); 1011} 1012 1013void TaskManagerModel::StartUpdating() { 1014 // Multiple StartUpdating requests may come in, and we only need to take 1015 // action the first time. 1016 update_requests_++; 1017 if (update_requests_ > 1) 1018 return; 1019 DCHECK_EQ(1, update_requests_); 1020 DCHECK_NE(TASK_PENDING, update_state_); 1021 1022 // If update_state_ is STOPPING, it means a task is still pending. Setting 1023 // it to TASK_PENDING ensures the tasks keep being posted (by Refresh()). 1024 if (update_state_ == IDLE) { 1025 MessageLoop::current()->PostTask( 1026 FROM_HERE, 1027 base::Bind(&TaskManagerModel::RefreshCallback, this)); 1028 } 1029 update_state_ = TASK_PENDING; 1030 1031 // Notify resource providers that we are updating. 1032 StartListening(); 1033 1034 if (!resources_.empty()) { 1035 FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_, 1036 OnReadyPeriodicalUpdate()); 1037 } 1038} 1039 1040void TaskManagerModel::StopUpdating() { 1041 // Don't actually stop updating until we have heard as many calls as those 1042 // to StartUpdating. 1043 update_requests_--; 1044 if (update_requests_ > 0) 1045 return; 1046 // Make sure that update_requests_ cannot go negative. 1047 CHECK_EQ(0, update_requests_); 1048 DCHECK_EQ(TASK_PENDING, update_state_); 1049 update_state_ = STOPPING; 1050 1051 // Notify resource providers that we are done updating. 1052 StopListening(); 1053} 1054 1055void TaskManagerModel::StartListening() { 1056 // Multiple StartListening requests may come in and we only need to take 1057 // action the first time. 1058 listen_requests_++; 1059 if (listen_requests_ > 1) 1060 return; 1061 DCHECK_EQ(1, listen_requests_); 1062 1063 // Notify resource providers that we should start listening to events. 1064 for (ResourceProviderList::iterator iter = providers_.begin(); 1065 iter != providers_.end(); ++iter) { 1066 (*iter)->StartUpdating(); 1067 } 1068} 1069 1070void TaskManagerModel::StopListening() { 1071 // Don't actually stop listening until we have heard as many calls as those 1072 // to StartListening. 1073 listen_requests_--; 1074 if (listen_requests_ > 0) 1075 return; 1076 1077 DCHECK_EQ(0, listen_requests_); 1078 1079 // Notify resource providers that we are done listening. 1080 for (ResourceProviderList::const_iterator iter = providers_.begin(); 1081 iter != providers_.end(); ++iter) { 1082 (*iter)->StopUpdating(); 1083 } 1084 1085 // Must clear the resources before the next attempt to start listening. 1086 Clear(); 1087} 1088 1089void TaskManagerModel::Clear() { 1090 int size = ResourceCount(); 1091 if (size > 0) { 1092 resources_.clear(); 1093 1094 // Clear the groups. 1095 STLDeleteValues(&group_map_); 1096 1097 // Clear the process related info. 1098 STLDeleteValues(&metrics_map_); 1099 1100 // Clear the network maps. 1101 current_byte_count_map_.clear(); 1102 1103 per_resource_cache_.clear(); 1104 per_process_cache_.clear(); 1105 1106 FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_, 1107 OnItemsRemoved(0, size)); 1108 } 1109 last_unique_id_ = 0; 1110} 1111 1112void TaskManagerModel::ModelChanged() { 1113 // Notify the table that the contents have changed for it to redraw. 1114 FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_, OnModelChanged()); 1115} 1116 1117void TaskManagerModel::NotifyResourceTypeStats( 1118 base::ProcessId renderer_id, 1119 const WebKit::WebCache::ResourceTypeStats& stats) { 1120 for (ResourceList::iterator it = resources_.begin(); 1121 it != resources_.end(); ++it) { 1122 if (base::GetProcId((*it)->GetProcess()) == renderer_id) { 1123 (*it)->NotifyResourceTypeStats(stats); 1124 } 1125 } 1126} 1127 1128void TaskManagerModel::NotifyFPS(base::ProcessId renderer_id, 1129 int routing_id, 1130 float fps) { 1131 for (ResourceList::iterator it = resources_.begin(); 1132 it != resources_.end(); ++it) { 1133 if (base::GetProcId((*it)->GetProcess()) == renderer_id && 1134 (*it)->GetRoutingID() == routing_id) { 1135 (*it)->NotifyFPS(fps); 1136 } 1137 } 1138} 1139 1140void TaskManagerModel::NotifyVideoMemoryUsageStats( 1141 const content::GPUVideoMemoryUsageStats& video_memory_usage_stats) { 1142 DCHECK(pending_video_memory_usage_stats_update_); 1143 video_memory_usage_stats_ = video_memory_usage_stats; 1144 pending_video_memory_usage_stats_update_ = false; 1145} 1146 1147void TaskManagerModel::NotifyV8HeapStats(base::ProcessId renderer_id, 1148 size_t v8_memory_allocated, 1149 size_t v8_memory_used) { 1150 for (ResourceList::iterator it = resources_.begin(); 1151 it != resources_.end(); ++it) { 1152 if (base::GetProcId((*it)->GetProcess()) == renderer_id) { 1153 (*it)->NotifyV8HeapStats(v8_memory_allocated, v8_memory_used); 1154 } 1155 } 1156} 1157 1158void TaskManagerModel::NotifyBytesRead(const net::URLRequest& request, 1159 int byte_count) { 1160 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 1161 1162 // Only net::URLRequestJob instances created by the ResourceDispatcherHost 1163 // have an associated ResourceRequestInfo. 1164 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(&request); 1165 1166 // have a render view associated. All other jobs will have -1 returned for 1167 // the render process child and routing ids - the jobs may still match a 1168 // resource based on their origin id, otherwise BytesRead() will attribute 1169 // the activity to the Browser resource. 1170 int render_process_host_child_id = -1, routing_id = -1; 1171 if (info) 1172 info->GetAssociatedRenderView(&render_process_host_child_id, &routing_id); 1173 1174 // Get the origin PID of the request's originator. This will only be set for 1175 // plugins - for renderer or browser initiated requests it will be zero. 1176 int origin_pid = 0; 1177 if (info) 1178 origin_pid = info->GetOriginPID(); 1179 1180 if (bytes_read_buffer_.empty()) { 1181 MessageLoop::current()->PostDelayedTask( 1182 FROM_HERE, 1183 base::Bind(&TaskManagerModel::NotifyMultipleBytesRead, this), 1184 base::TimeDelta::FromSeconds(1)); 1185 } 1186 1187 bytes_read_buffer_.push_back( 1188 BytesReadParam(origin_pid, render_process_host_child_id, 1189 routing_id, byte_count)); 1190} 1191 1192TaskManagerModel::~TaskManagerModel() { 1193} 1194 1195void TaskManagerModel::RefreshCallback() { 1196 DCHECK_NE(IDLE, update_state_); 1197 1198 if (update_state_ == STOPPING) { 1199 // We have been asked to stop. 1200 update_state_ = IDLE; 1201 return; 1202 } 1203 1204 Refresh(); 1205 1206 // Schedule the next update. 1207 MessageLoop::current()->PostDelayedTask( 1208 FROM_HERE, 1209 base::Bind(&TaskManagerModel::RefreshCallback, this), 1210 base::TimeDelta::FromMilliseconds(kUpdateTimeMs)); 1211} 1212 1213void TaskManagerModel::Refresh() { 1214 goat_salt_ = base::RandUint64(); 1215 1216 per_resource_cache_.clear(); 1217 per_process_cache_.clear(); 1218 1219 // Compute the CPU usage values. 1220 // Note that we compute the CPU usage for all resources (instead of doing it 1221 // lazily) as process_util::GetCPUUsage() returns the CPU usage since the last 1222 // time it was called, and not calling it everytime would skew the value the 1223 // next time it is retrieved (as it would be for more than 1 cycle). 1224 for (ResourceList::iterator iter = resources_.begin(); 1225 iter != resources_.end(); ++iter) { 1226 base::ProcessHandle process = (*iter)->GetProcess(); 1227 PerProcessValues& values(per_process_cache_[process]); 1228 if (values.is_cpu_usage_valid) 1229 continue; 1230 1231 values.is_cpu_usage_valid = true; 1232 MetricsMap::iterator metrics_iter = metrics_map_.find(process); 1233 DCHECK(metrics_iter != metrics_map_.end()); 1234 values.cpu_usage = metrics_iter->second->GetCPUUsage(); 1235 } 1236 1237 // Send a request to refresh GPU memory consumption values 1238 RefreshVideoMemoryUsageStats(); 1239 1240 // Compute the new network usage values. 1241 base::TimeDelta update_time = 1242 base::TimeDelta::FromMilliseconds(kUpdateTimeMs); 1243 for (ResourceValueMap::iterator iter = current_byte_count_map_.begin(); 1244 iter != current_byte_count_map_.end(); ++iter) { 1245 PerResourceValues* values = &(per_resource_cache_[iter->first]); 1246 if (update_time > base::TimeDelta::FromSeconds(1)) 1247 values->network_usage = iter->second / update_time.InSeconds(); 1248 else 1249 values->network_usage = iter->second * (1 / update_time.InSeconds()); 1250 1251 // Then we reset the current byte count. 1252 iter->second = 0; 1253 } 1254 1255 // Let resources update themselves if they need to. 1256 for (ResourceList::iterator iter = resources_.begin(); 1257 iter != resources_.end(); ++iter) { 1258 (*iter)->Refresh(); 1259 } 1260 1261 if (!resources_.empty()) { 1262 FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_, 1263 OnItemsChanged(0, ResourceCount())); 1264 } 1265} 1266 1267void TaskManagerModel::RefreshVideoMemoryUsageStats() { 1268 if (pending_video_memory_usage_stats_update_) 1269 return; 1270 1271 if (!video_memory_usage_stats_observer_.get()) { 1272 video_memory_usage_stats_observer_.reset( 1273 new TaskManagerModelGpuDataManagerObserver()); 1274 } 1275 pending_video_memory_usage_stats_update_ = true; 1276 content::GpuDataManager::GetInstance()->RequestVideoMemoryUsageStatsUpdate(); 1277} 1278 1279int64 TaskManagerModel::GetNetworkUsageForResource( 1280 TaskManager::Resource* resource) const { 1281 // Returns default of 0 if no network usage. 1282 return per_resource_cache_[resource].network_usage; 1283} 1284 1285void TaskManagerModel::BytesRead(BytesReadParam param) { 1286 if (update_state_ != TASK_PENDING || listen_requests_ == 0) { 1287 // A notification sneaked in while we were stopping the updating, just 1288 // ignore it. 1289 return; 1290 } 1291 1292 // TODO(jcampan): this should be improved once we have a better way of 1293 // linking a network notification back to the object that initiated it. 1294 TaskManager::Resource* resource = NULL; 1295 for (ResourceProviderList::iterator iter = providers_.begin(); 1296 iter != providers_.end(); ++iter) { 1297 resource = (*iter)->GetResource(param.origin_pid, 1298 param.render_process_host_child_id, 1299 param.routing_id); 1300 if (resource) 1301 break; 1302 } 1303 1304 if (resource == NULL) { 1305 // We can't match a resource to the notification. That might mean the 1306 // tab that started a download was closed, or the request may have had 1307 // no originating resource associated with it in the first place. 1308 // We attribute orphaned/unaccounted activity to the Browser process. 1309 CHECK(param.origin_pid || (param.render_process_host_child_id != -1)); 1310 param.origin_pid = 0; 1311 param.render_process_host_child_id = param.routing_id = -1; 1312 BytesRead(param); 1313 return; 1314 } 1315 1316 // We do support network usage, mark the resource as such so it can report 0 1317 // instead of N/A. 1318 if (!resource->SupportNetworkUsage()) 1319 resource->SetSupportNetworkUsage(); 1320 1321 ResourceValueMap::const_iterator iter_res = 1322 current_byte_count_map_.find(resource); 1323 if (iter_res == current_byte_count_map_.end()) 1324 current_byte_count_map_[resource] = param.byte_count; 1325 else 1326 current_byte_count_map_[resource] = iter_res->second + param.byte_count; 1327} 1328 1329void TaskManagerModel::MultipleBytesRead( 1330 const std::vector<BytesReadParam>* params) { 1331 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1332 for (std::vector<BytesReadParam>::const_iterator it = params->begin(); 1333 it != params->end(); ++it) { 1334 BytesRead(*it); 1335 } 1336} 1337 1338void TaskManagerModel::NotifyMultipleBytesRead() { 1339 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 1340 DCHECK(!bytes_read_buffer_.empty()); 1341 1342 std::vector<BytesReadParam>* bytes_read_buffer = 1343 new std::vector<BytesReadParam>; 1344 bytes_read_buffer_.swap(*bytes_read_buffer); 1345 BrowserThread::PostTask( 1346 BrowserThread::UI, FROM_HERE, 1347 base::Bind(&TaskManagerModel::MultipleBytesRead, this, 1348 base::Owned(bytes_read_buffer))); 1349} 1350 1351int64 TaskManagerModel::GetNetworkUsage(TaskManager::Resource* resource) const { 1352 int64 net_usage = GetNetworkUsageForResource(resource); 1353 if (net_usage == 0 && !resource->SupportNetworkUsage()) 1354 return -1; 1355 return net_usage; 1356} 1357 1358double TaskManagerModel::GetCPUUsage(TaskManager::Resource* resource) const { 1359 const PerProcessValues& values(per_process_cache_[resource->GetProcess()]); 1360 // Returns 0 if not valid, which is fine. 1361 return values.cpu_usage; 1362} 1363 1364string16 TaskManagerModel::GetMemCellText(int64 number) const { 1365#if !defined(OS_MACOSX) 1366 string16 str = base::FormatNumber(number / 1024); 1367 1368 // Adjust number string if necessary. 1369 base::i18n::AdjustStringForLocaleDirection(&str); 1370 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_MEM_CELL_TEXT, str); 1371#else 1372 // System expectation is to show "100 kB", "200 MB", etc. 1373 // TODO(thakis): Switch to metric units (as opposed to powers of two). 1374 return ui::FormatBytes(number); 1375#endif 1376} 1377 1378bool TaskManagerModel::CachePrivateAndSharedMemory( 1379 base::ProcessHandle handle) const { 1380 PerProcessValues& values(per_process_cache_[handle]); 1381 if (values.is_private_and_shared_valid) 1382 return true; 1383 1384 MetricsMap::const_iterator iter = metrics_map_.find(handle); 1385 if (iter == metrics_map_.end() || 1386 !iter->second->GetMemoryBytes(&values.private_bytes, 1387 &values.shared_bytes)) { 1388 return false; 1389 } 1390 1391 values.is_private_and_shared_valid = true; 1392 return true; 1393} 1394 1395bool TaskManagerModel::CacheWebCoreStats(int index) const { 1396 PerResourceValues& values(GetPerResourceValues(index)); 1397 if (!values.is_webcore_stats_valid) { 1398 if (!GetResource(index)->ReportsCacheStats()) 1399 return false; 1400 values.is_webcore_stats_valid = true; 1401 values.webcore_stats = GetResource(index)->GetWebCoreCacheStats(); 1402 } 1403 return true; 1404} 1405 1406bool TaskManagerModel::CacheV8Memory(int index) const { 1407 PerResourceValues& values(GetPerResourceValues(index)); 1408 if (!values.is_v8_memory_valid) { 1409 if (!GetResource(index)->ReportsV8MemoryStats()) 1410 return false; 1411 values.is_v8_memory_valid = true; 1412 values.v8_memory_allocated = GetResource(index)->GetV8MemoryAllocated(); 1413 values.v8_memory_used = GetResource(index)->GetV8MemoryUsed(); 1414 } 1415 return true; 1416} 1417 1418void TaskManagerModel::AddResourceProvider( 1419 TaskManager::ResourceProvider* provider) { 1420 DCHECK(provider); 1421 providers_.push_back(provider); 1422} 1423 1424TaskManagerModel::PerResourceValues& TaskManagerModel::GetPerResourceValues( 1425 int index) const { 1426 return per_resource_cache_[GetResource(index)]; 1427} 1428 1429TaskManager::Resource* TaskManagerModel::GetResource(int index) const { 1430 CHECK_GE(index, 0); 1431 CHECK_LT(index, static_cast<int>(resources_.size())); 1432 return resources_[index]; 1433} 1434 1435//////////////////////////////////////////////////////////////////////////////// 1436// TaskManager class 1437//////////////////////////////////////////////////////////////////////////////// 1438 1439int TaskManager::Resource::GetRoutingID() const { return 0; } 1440 1441bool TaskManager::Resource::ReportsCacheStats() const { return false; } 1442 1443WebKit::WebCache::ResourceTypeStats 1444TaskManager::Resource::GetWebCoreCacheStats() const { 1445 return WebKit::WebCache::ResourceTypeStats(); 1446} 1447 1448bool TaskManager::Resource::ReportsFPS() const { return false; } 1449 1450float TaskManager::Resource::GetFPS() const { return 0.0f; } 1451 1452bool TaskManager::Resource::ReportsSqliteMemoryUsed() const { return false; } 1453 1454size_t TaskManager::Resource::SqliteMemoryUsedBytes() const { return 0; } 1455 1456const extensions::Extension* TaskManager::Resource::GetExtension() const { 1457 return NULL; 1458} 1459 1460bool TaskManager::Resource::ReportsV8MemoryStats() const { return false; } 1461 1462size_t TaskManager::Resource::GetV8MemoryAllocated() const { return 0; } 1463 1464size_t TaskManager::Resource::GetV8MemoryUsed() const { return 0; } 1465 1466bool TaskManager::Resource::CanInspect() const { return false; } 1467 1468content::WebContents* TaskManager::Resource::GetWebContents() const { 1469 return NULL; 1470} 1471 1472bool TaskManager::Resource::IsBackground() const { return false; } 1473 1474// static 1475void TaskManager::RegisterPrefs(PrefRegistrySimple* registry) { 1476 registry->RegisterDictionaryPref(prefs::kTaskManagerWindowPlacement); 1477} 1478 1479bool TaskManager::IsBrowserProcess(int index) const { 1480 // If some of the selection is out of bounds, ignore. This may happen when 1481 // killing a process that manages several pages. 1482 return index < model_->ResourceCount() && 1483 model_->GetProcess(index) == base::GetCurrentProcessHandle(); 1484} 1485 1486void TaskManager::KillProcess(int index) { 1487 base::ProcessHandle process = model_->GetProcess(index); 1488 DCHECK(process); 1489 if (process != base::GetCurrentProcessHandle()) 1490 base::KillProcess(process, content::RESULT_CODE_KILLED, false); 1491} 1492 1493void TaskManager::ActivateProcess(int index) { 1494 // GetResourceWebContents returns a pointer to the relevant web contents for 1495 // the resource. If the index doesn't correspond to any web contents 1496 // (i.e. refers to the Browser process or a plugin), GetWebContents will 1497 // return NULL. 1498 WebContents* chosen_web_contents = model_->GetResourceWebContents(index); 1499 if (chosen_web_contents && chosen_web_contents->GetDelegate()) 1500 chosen_web_contents->GetDelegate()->ActivateContents(chosen_web_contents); 1501} 1502 1503void TaskManager::AddResource(Resource* resource) { 1504 model_->AddResource(resource); 1505} 1506 1507void TaskManager::RemoveResource(Resource* resource) { 1508 model_->RemoveResource(resource); 1509} 1510 1511void TaskManager::OnWindowClosed() { 1512 model_->StopUpdating(); 1513} 1514 1515void TaskManager::ModelChanged() { 1516 model_->ModelChanged(); 1517} 1518 1519// static 1520TaskManager* TaskManager::GetInstance() { 1521 return Singleton<TaskManager>::get(); 1522} 1523 1524void TaskManager::OpenAboutMemory(chrome::HostDesktopType desktop_type) { 1525 Browser* browser = chrome::FindOrCreateTabbedBrowser( 1526 ProfileManager::GetDefaultProfileOrOffTheRecord(), desktop_type); 1527 chrome::NavigateParams params(browser, GURL(chrome::kChromeUIMemoryURL), 1528 content::PAGE_TRANSITION_LINK); 1529 params.disposition = NEW_FOREGROUND_TAB; 1530 chrome::Navigate(¶ms); 1531} 1532 1533namespace { 1534 1535// Counts the number of extension background pages associated with this profile. 1536int CountExtensionBackgroundPagesForProfile(Profile* profile) { 1537 int count = 0; 1538 ExtensionProcessManager* manager = 1539 extensions::ExtensionSystem::Get(profile)->process_manager(); 1540 if (!manager) 1541 return count; 1542 1543 const ExtensionProcessManager::ExtensionHostSet& background_hosts = 1544 manager->background_hosts(); 1545 for (ExtensionProcessManager::const_iterator iter = background_hosts.begin(); 1546 iter != background_hosts.end(); ++iter) { 1547 ++count; 1548 } 1549 return count; 1550} 1551 1552} // namespace 1553 1554// static 1555int TaskManager::GetBackgroundPageCount() { 1556 int count = 0; 1557 ProfileManager* profile_manager = g_browser_process->profile_manager(); 1558 if (!profile_manager) // Null when running unit tests. 1559 return count; 1560 std::vector<Profile*> profiles(profile_manager->GetLoadedProfiles()); 1561 for (std::vector<Profile*>::const_iterator iter = profiles.begin(); 1562 iter != profiles.end(); 1563 ++iter) { 1564 Profile* profile = *iter; 1565 // Count the number of Background Contents (background pages for hosted 1566 // apps). Incognito windows do not support hosted apps, so just check the 1567 // main profile. 1568 BackgroundContentsService* background_contents_service = 1569 BackgroundContentsServiceFactory::GetForProfile(profile); 1570 if (background_contents_service) 1571 count += background_contents_service->GetBackgroundContents().size(); 1572 1573 // Count the number of extensions with background pages (including 1574 // incognito). 1575 count += CountExtensionBackgroundPagesForProfile(profile); 1576 if (profile->HasOffTheRecordProfile()) { 1577 count += CountExtensionBackgroundPagesForProfile( 1578 profile->GetOffTheRecordProfile()); 1579 } 1580 } 1581 return count; 1582} 1583 1584TaskManager::TaskManager() 1585 : ALLOW_THIS_IN_INITIALIZER_LIST(model_(new TaskManagerModel(this))) { 1586} 1587 1588TaskManager::~TaskManager() { 1589} 1590