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