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