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 54 using content::BrowserThread; 55 using content::ResourceRequestInfo; 56 using content::WebContents; 57 using task_manager::Resource; 58 using task_manager::ResourceProvider; 59 60 class Profile; 61 62 namespace { 63 64 template <class T> 65 int 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. 74 int 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. 82 template <class T> 83 int 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 95 string16 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. 102 bool 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) 122 void 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 139 void 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. 158 int 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 176 class 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 208 TaskManagerModel::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 226 TaskManagerModel::PerResourceValues::~PerResourceValues() { 227 } 228 229 TaskManagerModel::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 248 TaskManagerModel::PerProcessValues::~PerProcessValues() { 249 } 250 251 //////////////////////////////////////////////////////////////////////////////// 252 // TaskManagerModel class 253 //////////////////////////////////////////////////////////////////////////////// 254 255 TaskManagerModel::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 285 void TaskManagerModel::AddObserver(TaskManagerModelObserver* observer) { 286 observer_list_.AddObserver(observer); 287 } 288 289 void TaskManagerModel::RemoveObserver(TaskManagerModelObserver* observer) { 290 observer_list_.RemoveObserver(observer); 291 } 292 293 int TaskManagerModel::ResourceCount() const { 294 return resources_.size(); 295 } 296 297 int TaskManagerModel::GroupCount() const { 298 return group_map_.size(); 299 } 300 301 int64 TaskManagerModel::GetNetworkUsage(int index) const { 302 return GetNetworkUsage(GetResource(index)); 303 } 304 305 double TaskManagerModel::GetCPUUsage(int index) const { 306 return GetCPUUsage(GetResource(index)); 307 } 308 309 base::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 318 base::ProcessHandle TaskManagerModel::GetProcess(int index) const { 319 return GetResource(index)->GetProcess(); 320 } 321 322 int TaskManagerModel::GetResourceUniqueId(int index) const { 323 return GetResource(index)->get_unique_id(); 324 } 325 326 int 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 335 string16 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 400 const 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 409 const 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 418 string16 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 429 string16 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 441 string16 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 448 string16 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 455 string16 TaskManagerModel::GetResourcePhysicalMemory(int index) const { 456 size_t phys_mem; 457 GetPhysicalMemory(index, &phys_mem); 458 return GetMemCellText(phys_mem); 459 } 460 461 string16 TaskManagerModel::GetResourceProcessId(int index) const { 462 return base::IntToString16(GetProcessId(index)); 463 } 464 465 string16 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 472 string16 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 479 string16 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 486 string16 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 493 string16 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 501 string16 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 512 string16 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 520 string16 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 527 string16 TaskManagerModel::GetResourceGoatsTeleported(int index) const { 528 CHECK_LT(index, ResourceCount()); 529 return base::FormatNumber(GetGoatsTeleported(index)); 530 } 531 532 string16 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 547 bool 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 556 bool 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 565 bool 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 593 void 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 613 void 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 633 bool 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 642 bool 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 665 bool 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 678 bool 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 693 bool 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 701 bool 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 709 bool TaskManagerModel::CanActivate(int index) const { 710 CHECK_LT(index, ResourceCount()); 711 return GetResourceWebContents(index) != NULL; 712 } 713 714 bool TaskManagerModel::CanInspect(int index) const { 715 return GetResource(index)->CanInspect(); 716 } 717 718 void TaskManagerModel::Inspect(int index) const { 719 CHECK_LT(index, ResourceCount()); 720 GetResource(index)->Inspect(); 721 } 722 723 int 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 733 bool 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 741 bool 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 749 bool TaskManagerModel::IsBackgroundResource(int index) const { 750 return GetResource(index)->IsBackground(); 751 } 752 753 gfx::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 763 TaskManagerModel::GroupRange 764 TaskManagerModel::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 783 int 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 794 int 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 815 int 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 945 int TaskManagerModel::GetUniqueChildProcessId(int index) const { 946 return GetResource(index)->GetUniqueChildProcessId(); 947 } 948 949 Resource::Type TaskManagerModel::GetResourceType(int index) const { 950 return GetResource(index)->GetType(); 951 } 952 953 WebContents* TaskManagerModel::GetResourceWebContents(int index) const { 954 return GetResource(index)->GetWebContents(); 955 } 956 957 const extensions::Extension* TaskManagerModel::GetResourceExtension( 958 int index) const { 959 return GetResource(index)->GetExtension(); 960 } 961 962 void 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 1010 void 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 1062 void 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 1089 void 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 1104 void 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 1119 void 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 1138 void 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 1161 void 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 1166 void 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 1177 void 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 1189 void 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 1196 void 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 1207 void 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 1241 TaskManagerModel::~TaskManagerModel() { 1242 } 1243 1244 void 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 1262 void 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 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 string16 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 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 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 1545 TaskManager::TaskManager() 1546 : model_(new TaskManagerModel(this)) { 1547 } 1548 1549 TaskManager::~TaskManager() { 1550 } 1551