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