Give names to all utility processes.
[chromium-blink-merge.git] / chrome / browser / task_manager / task_manager.cc
blobc9df8ec2b9bfebfe96682c4800f78fbc2d308579
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.
5 #include "chrome/browser/task_manager/task_manager.h"
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/prefs/pref_service.h"
12 #include "base/process/process_metrics.h"
13 #include "base/profiler/scoped_tracker.h"
14 #include "base/stl_util.h"
15 #include "base/strings/string16.h"
16 #include "base/strings/string_number_conversions.h"
17 #include "base/strings/stringprintf.h"
18 #include "base/strings/utf_string_conversions.h"
19 #include "chrome/browser/browser_process.h"
20 #include "chrome/browser/profiles/profile_manager.h"
21 #include "chrome/browser/profiles/profile_window.h"
22 #include "chrome/browser/task_manager/background_information.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_information.h"
26 #include "chrome/browser/task_manager/guest_information.h"
27 #include "chrome/browser/task_manager/panel_information.h"
28 #include "chrome/browser/task_manager/printing_information.h"
29 #include "chrome/browser/task_manager/resource_provider.h"
30 #include "chrome/browser/task_manager/tab_contents_information.h"
31 #include "chrome/browser/task_manager/web_contents_resource_provider.h"
32 #include "chrome/browser/ui/browser_navigator.h"
33 #include "chrome/browser/ui/user_manager.h"
34 #include "chrome/common/pref_names.h"
35 #include "chrome/common/url_constants.h"
36 #include "chrome/grit/generated_resources.h"
37 #include "components/nacl/browser/nacl_browser.h"
38 #include "content/public/browser/browser_thread.h"
39 #include "content/public/browser/gpu_data_manager.h"
40 #include "content/public/browser/gpu_data_manager_observer.h"
41 #include "content/public/browser/resource_request_info.h"
42 #include "content/public/browser/web_contents.h"
43 #include "content/public/browser/web_contents_delegate.h"
44 #include "content/public/browser/worker_service.h"
45 #include "content/public/common/result_codes.h"
46 #include "extensions/browser/extension_system.h"
47 #include "third_party/icu/source/i18n/unicode/coll.h"
48 #include "ui/base/l10n/l10n_util.h"
49 #include "ui/base/resource/resource_bundle.h"
50 #include "ui/base/text/bytes_formatting.h"
51 #include "ui/gfx/image/image_skia.h"
52 #include "ui/resources/grit/ui_resources.h"
54 #if defined(OS_MACOSX)
55 #include "content/public/browser/browser_child_process_host.h"
56 #endif
58 using content::BrowserThread;
59 using content::ResourceRequestInfo;
60 using content::WebContents;
61 using task_manager::Resource;
62 using task_manager::ResourceProvider;
63 using task_manager::WebContentsInformation;
65 class Profile;
67 namespace {
69 template <class T>
70 int ValueCompare(T value1, T value2) {
71 if (value1 < value2)
72 return -1;
73 if (value1 == value2)
74 return 0;
75 return 1;
78 // Used when one or both of the results to compare are unavailable.
79 int OrderUnavailableValue(bool v1, bool v2) {
80 if (!v1 && !v2)
81 return 0;
82 return v1 ? 1 : -1;
85 // Used by TaskManagerModel::CompareValues(). See it for details of return
86 // value.
87 template <class T>
88 int ValueCompareMember(const TaskManagerModel* model,
89 bool (TaskManagerModel::*f)(int, T*) const,
90 int row1,
91 int row2) {
92 T value1;
93 T value2;
94 bool value1_valid = (model->*f)(row1, &value1);
95 bool value2_valid = (model->*f)(row2, &value2);
96 return value1_valid && value2_valid ? ValueCompare(value1, value2) :
97 OrderUnavailableValue(value1_valid, value2_valid);
100 base::string16 FormatStatsSize(const blink::WebCache::ResourceTypeStat& stat) {
101 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_CACHE_SIZE_CELL_TEXT,
102 ui::FormatBytesWithUnits(stat.size, ui::DATA_UNITS_KIBIBYTE, false),
103 ui::FormatBytesWithUnits(stat.liveSize, ui::DATA_UNITS_KIBIBYTE, false));
106 // Returns true if the specified id should use the first value in the group.
107 bool IsSharedByGroup(int col_id) {
108 switch (col_id) {
109 case IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN:
110 case IDS_TASK_MANAGER_SHARED_MEM_COLUMN:
111 case IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN:
112 case IDS_TASK_MANAGER_CPU_COLUMN:
113 case IDS_TASK_MANAGER_PROCESS_ID_COLUMN:
114 case IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN:
115 case IDS_TASK_MANAGER_VIDEO_MEMORY_COLUMN:
116 case IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN:
117 case IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN:
118 case IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN:
119 case IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN:
120 case IDS_TASK_MANAGER_NACL_DEBUG_STUB_PORT_COLUMN:
121 return true;
122 default:
123 return false;
127 #if defined(OS_WIN)
128 void GetWinGDIHandles(base::ProcessHandle process,
129 size_t* current,
130 size_t* peak) {
131 *current = 0;
132 *peak = 0;
133 // Get a handle to |process| that has PROCESS_QUERY_INFORMATION rights.
134 HANDLE current_process = GetCurrentProcess();
135 HANDLE process_with_query_rights;
136 if (DuplicateHandle(current_process, process, current_process,
137 &process_with_query_rights, PROCESS_QUERY_INFORMATION,
138 false, 0)) {
139 *current = GetGuiResources(process_with_query_rights, GR_GDIOBJECTS);
140 *peak = GetGuiResources(process_with_query_rights, GR_GDIOBJECTS_PEAK);
141 CloseHandle(process_with_query_rights);
145 void GetWinUSERHandles(base::ProcessHandle process,
146 size_t* current,
147 size_t* peak) {
148 *current = 0;
149 *peak = 0;
150 // Get a handle to |process| that has PROCESS_QUERY_INFORMATION rights.
151 HANDLE current_process = GetCurrentProcess();
152 HANDLE process_with_query_rights;
153 if (DuplicateHandle(current_process, process, current_process,
154 &process_with_query_rights, PROCESS_QUERY_INFORMATION,
155 false, 0)) {
156 *current = GetGuiResources(process_with_query_rights, GR_USEROBJECTS);
157 *peak = GetGuiResources(process_with_query_rights, GR_USEROBJECTS_PEAK);
158 CloseHandle(process_with_query_rights);
161 #endif
163 } // namespace
165 class TaskManagerModelGpuDataManagerObserver
166 : public content::GpuDataManagerObserver {
167 public:
168 TaskManagerModelGpuDataManagerObserver() {
169 content::GpuDataManager::GetInstance()->AddObserver(this);
172 ~TaskManagerModelGpuDataManagerObserver() override {
173 content::GpuDataManager::GetInstance()->RemoveObserver(this);
176 static void NotifyVideoMemoryUsageStats(
177 const content::GPUVideoMemoryUsageStats& video_memory_usage_stats) {
178 TaskManager::GetInstance()->model()->NotifyVideoMemoryUsageStats(
179 video_memory_usage_stats);
182 void OnVideoMemoryUsageStatsUpdate(const content::GPUVideoMemoryUsageStats&
183 video_memory_usage_stats) override {
184 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
185 NotifyVideoMemoryUsageStats(video_memory_usage_stats);
186 } else {
187 BrowserThread::PostTask(
188 BrowserThread::UI, FROM_HERE, base::Bind(
189 &TaskManagerModelGpuDataManagerObserver::
190 NotifyVideoMemoryUsageStats,
191 video_memory_usage_stats));
196 TaskManagerModel::PerResourceValues::PerResourceValues()
197 : is_title_valid(false),
198 is_profile_name_valid(false),
199 network_usage(0),
200 is_process_id_valid(false),
201 process_id(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) {}
209 TaskManagerModel::PerResourceValues::~PerResourceValues() {}
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) {}
233 TaskManagerModel::PerProcessValues::~PerProcessValues() {}
235 ////////////////////////////////////////////////////////////////////////////////
236 // TaskManagerModel class
237 ////////////////////////////////////////////////////////////////////////////////
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 is_updating_byte_count_(false) {
245 // TODO(vadimt): Remove ScopedTracker below once crbug.com/437890 is fixed.
246 tracked_objects::ScopedTracker tracking_profile1(
247 FROM_HERE_WITH_EXPLICIT_FUNCTION(
248 "437890 TaskManagerModel::TaskManagerModel1"));
250 AddResourceProvider(
251 new task_manager::BrowserProcessResourceProvider(task_manager));
253 // TODO(vadimt): Remove ScopedTracker below once crbug.com/437890 is fixed.
254 tracked_objects::ScopedTracker tracking_profile2(
255 FROM_HERE_WITH_EXPLICIT_FUNCTION(
256 "437890 TaskManagerModel::TaskManagerModel2"));
258 AddResourceProvider(new task_manager::WebContentsResourceProvider(
259 task_manager,
260 scoped_ptr<WebContentsInformation>(
261 new task_manager::BackgroundInformation())));
263 // TODO(vadimt): Remove ScopedTracker below once crbug.com/437890 is fixed.
264 tracked_objects::ScopedTracker tracking_profile3(
265 FROM_HERE_WITH_EXPLICIT_FUNCTION(
266 "437890 TaskManagerModel::TaskManagerModel3"));
268 AddResourceProvider(new task_manager::WebContentsResourceProvider(
269 task_manager,
270 scoped_ptr<WebContentsInformation>(
271 new task_manager::TabContentsInformation())));
272 #if defined(ENABLE_PRINT_PREVIEW)
274 // TODO(vadimt): Remove ScopedTracker below once crbug.com/437890 is fixed.
275 tracked_objects::ScopedTracker tracking_profile4(
276 FROM_HERE_WITH_EXPLICIT_FUNCTION(
277 "437890 TaskManagerModel::TaskManagerModel4"));
279 AddResourceProvider(new task_manager::WebContentsResourceProvider(
280 task_manager,
281 scoped_ptr<WebContentsInformation>(
282 new task_manager::PrintingInformation())));
283 #endif // ENABLE_PRINT_PREVIEW
285 // TODO(vadimt): Remove ScopedTracker below once crbug.com/437890 is fixed.
286 tracked_objects::ScopedTracker tracking_profile5(
287 FROM_HERE_WITH_EXPLICIT_FUNCTION(
288 "437890 TaskManagerModel::TaskManagerModel5"));
290 AddResourceProvider(new task_manager::WebContentsResourceProvider(
291 task_manager,
292 scoped_ptr<WebContentsInformation>(
293 new task_manager::PanelInformation())));
295 // TODO(vadimt): Remove ScopedTracker below once crbug.com/437890 is fixed.
296 tracked_objects::ScopedTracker tracking_profile6(
297 FROM_HERE_WITH_EXPLICIT_FUNCTION(
298 "437890 TaskManagerModel::TaskManagerModel6"));
300 AddResourceProvider(
301 new task_manager::ChildProcessResourceProvider(task_manager));
303 // TODO(vadimt): Remove ScopedTracker below once crbug.com/437890 is fixed.
304 tracked_objects::ScopedTracker tracking_profile7(
305 FROM_HERE_WITH_EXPLICIT_FUNCTION(
306 "437890 TaskManagerModel::TaskManagerModel7"));
308 AddResourceProvider(new task_manager::WebContentsResourceProvider(
309 task_manager,
310 scoped_ptr<WebContentsInformation>(
311 new task_manager::ExtensionInformation())));
313 // TODO(vadimt): Remove ScopedTracker below once crbug.com/437890 is fixed.
314 tracked_objects::ScopedTracker tracking_profile8(
315 FROM_HERE_WITH_EXPLICIT_FUNCTION(
316 "437890 TaskManagerModel::TaskManagerModel8"));
318 AddResourceProvider(new task_manager::WebContentsResourceProvider(
319 task_manager,
320 scoped_ptr<WebContentsInformation>(
321 new task_manager::GuestInformation())));
324 void TaskManagerModel::AddObserver(TaskManagerModelObserver* observer) {
325 observer_list_.AddObserver(observer);
328 void TaskManagerModel::RemoveObserver(TaskManagerModelObserver* observer) {
329 observer_list_.RemoveObserver(observer);
332 int TaskManagerModel::ResourceCount() const {
333 return resources_.size();
336 int TaskManagerModel::GroupCount() const {
337 return group_map_.size();
340 int TaskManagerModel::GetNaClDebugStubPort(int index) const {
341 base::ProcessHandle handle = GetResource(index)->GetProcess();
342 PerProcessValues& values(per_process_cache_[handle]);
343 if (!values.is_nacl_debug_stub_port_valid) {
344 return nacl::kGdbDebugStubPortUnknown;
346 return values.nacl_debug_stub_port;
349 int64 TaskManagerModel::GetNetworkUsage(int index) const {
350 return GetNetworkUsage(GetResource(index));
353 double TaskManagerModel::GetCPUUsage(int index) const {
354 return GetCPUUsage(GetResource(index));
357 int TaskManagerModel::GetIdleWakeupsPerSecond(int index) const {
358 return GetIdleWakeupsPerSecond(GetResource(index));
361 base::ProcessId TaskManagerModel::GetProcessId(int index) const {
362 PerResourceValues& values(GetPerResourceValues(index));
363 if (!values.is_process_id_valid) {
364 values.is_process_id_valid = true;
365 values.process_id = base::GetProcId(GetResource(index)->GetProcess());
367 return values.process_id;
370 base::ProcessHandle TaskManagerModel::GetProcess(int index) const {
371 return GetResource(index)->GetProcess();
374 base::string16 TaskManagerModel::GetResourceById(int index, int col_id) const {
375 if (IsSharedByGroup(col_id) && !IsResourceFirstInGroup(index))
376 return base::string16();
378 switch (col_id) {
379 case IDS_TASK_MANAGER_TASK_COLUMN:
380 return GetResourceTitle(index);
382 case IDS_TASK_MANAGER_PROFILE_NAME_COLUMN:
383 return GetResourceProfileName(index);
385 case IDS_TASK_MANAGER_NET_COLUMN:
386 return GetResourceNetworkUsage(index);
388 case IDS_TASK_MANAGER_CPU_COLUMN:
389 return GetResourceCPUUsage(index);
391 case IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN:
392 return GetResourcePrivateMemory(index);
394 case IDS_TASK_MANAGER_SHARED_MEM_COLUMN:
395 return GetResourceSharedMemory(index);
397 case IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN:
398 return GetResourcePhysicalMemory(index);
400 case IDS_TASK_MANAGER_PROCESS_ID_COLUMN:
401 return GetResourceProcessId(index);
403 case IDS_TASK_MANAGER_GDI_HANDLES_COLUMN:
404 return GetResourceGDIHandles(index);
406 case IDS_TASK_MANAGER_USER_HANDLES_COLUMN:
407 return GetResourceUSERHandles(index);
409 case IDS_TASK_MANAGER_IDLE_WAKEUPS_COLUMN:
410 return GetResourceIdleWakeupsPerSecond(index);
412 case IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN:
413 return GetResourceWebCoreImageCacheSize(index);
415 case IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN:
416 return GetResourceWebCoreScriptsCacheSize(index);
418 case IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN:
419 return GetResourceWebCoreCSSCacheSize(index);
421 case IDS_TASK_MANAGER_VIDEO_MEMORY_COLUMN:
422 return GetResourceVideoMemory(index);
424 case IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN:
425 return GetResourceSqliteMemoryUsed(index);
427 case IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN:
428 return GetResourceV8MemoryAllocatedSize(index);
430 case IDS_TASK_MANAGER_NACL_DEBUG_STUB_PORT_COLUMN:
431 return GetResourceNaClDebugStubPort(index);
433 default:
434 NOTREACHED();
435 return base::string16();
439 const base::string16& TaskManagerModel::GetResourceTitle(int index) const {
440 PerResourceValues& values = GetPerResourceValues(index);
441 if (!values.is_title_valid) {
442 values.is_title_valid = true;
443 values.title = GetResource(index)->GetTitle();
445 return values.title;
448 const base::string16& TaskManagerModel::GetResourceProfileName(
449 int index) const {
450 PerResourceValues& values(GetPerResourceValues(index));
451 if (!values.is_profile_name_valid) {
452 values.is_profile_name_valid = true;
453 values.profile_name = GetResource(index)->GetProfileName();
455 return values.profile_name;
458 base::string16 TaskManagerModel::GetResourceNaClDebugStubPort(int index) const {
459 int port = GetNaClDebugStubPort(index);
460 if (port == nacl::kGdbDebugStubPortUnknown) {
461 return base::ASCIIToUTF16("Unknown");
462 } else if (port == nacl::kGdbDebugStubPortUnused) {
463 return base::ASCIIToUTF16("N/A");
464 } else {
465 return base::IntToString16(port);
469 base::string16 TaskManagerModel::GetResourceNetworkUsage(int index) const {
470 int64 net_usage = GetNetworkUsage(index);
471 if (net_usage == -1)
472 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT);
473 if (net_usage == 0)
474 return base::ASCIIToUTF16("0");
475 base::string16 net_byte = ui::FormatSpeed(net_usage);
476 // Force number string to have LTR directionality.
477 return base::i18n::GetDisplayStringInLTRDirectionality(net_byte);
480 base::string16 TaskManagerModel::GetResourceCPUUsage(int index) const {
481 return base::UTF8ToUTF16(base::StringPrintf(
482 #if defined(OS_MACOSX)
483 // Activity Monitor shows %cpu with one decimal digit -- be
484 // consistent with that.
485 "%.1f",
486 #else
487 "%.0f",
488 #endif
489 GetCPUUsage(GetResource(index))));
492 base::string16 TaskManagerModel::GetResourcePrivateMemory(int index) const {
493 size_t private_mem;
494 if (!GetPrivateMemory(index, &private_mem))
495 return base::ASCIIToUTF16("N/A");
496 return GetMemCellText(private_mem);
499 base::string16 TaskManagerModel::GetResourceSharedMemory(int index) const {
500 size_t shared_mem;
501 if (!GetSharedMemory(index, &shared_mem))
502 return base::ASCIIToUTF16("N/A");
503 return GetMemCellText(shared_mem);
506 base::string16 TaskManagerModel::GetResourcePhysicalMemory(int index) const {
507 size_t phys_mem;
508 GetPhysicalMemory(index, &phys_mem);
509 return GetMemCellText(phys_mem);
512 base::string16 TaskManagerModel::GetResourceProcessId(int index) const {
513 return base::IntToString16(GetProcessId(index));
516 base::string16 TaskManagerModel::GetResourceGDIHandles(int index) const {
517 size_t current, peak;
518 GetGDIHandles(index, &current, &peak);
519 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_HANDLES_CELL_TEXT,
520 base::IntToString16(current), base::IntToString16(peak));
523 base::string16 TaskManagerModel::GetResourceUSERHandles(int index) const {
524 size_t current, peak;
525 GetUSERHandles(index, &current, &peak);
526 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_HANDLES_CELL_TEXT,
527 base::IntToString16(current), base::IntToString16(peak));
530 base::string16 TaskManagerModel::GetResourceWebCoreImageCacheSize(
531 int index) const {
532 if (!CacheWebCoreStats(index))
533 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT);
534 return FormatStatsSize(GetPerResourceValues(index).webcore_stats.images);
537 base::string16 TaskManagerModel::GetResourceWebCoreScriptsCacheSize(
538 int index) const {
539 if (!CacheWebCoreStats(index))
540 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT);
541 return FormatStatsSize(GetPerResourceValues(index).webcore_stats.scripts);
544 base::string16 TaskManagerModel::GetResourceWebCoreCSSCacheSize(
545 int index) const {
546 if (!CacheWebCoreStats(index))
547 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT);
548 return FormatStatsSize(
549 GetPerResourceValues(index).webcore_stats.cssStyleSheets);
552 base::string16 TaskManagerModel::GetResourceVideoMemory(int index) const {
553 size_t video_memory;
554 bool has_duplicates;
555 if (!GetVideoMemory(index, &video_memory, &has_duplicates) || !video_memory)
556 return base::ASCIIToUTF16("N/A");
557 if (has_duplicates) {
558 return GetMemCellText(video_memory) + base::ASCIIToUTF16("*");
560 return GetMemCellText(video_memory);
563 base::string16 TaskManagerModel::GetResourceSqliteMemoryUsed(int index) const {
564 size_t bytes = 0;
565 if (!GetSqliteMemoryUsedBytes(index, &bytes))
566 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT);
567 return GetMemCellText(bytes);
570 base::string16 TaskManagerModel::GetResourceIdleWakeupsPerSecond(int index)
571 const {
572 return base::FormatNumber(GetIdleWakeupsPerSecond(GetResource(index)));
575 base::string16 TaskManagerModel::GetResourceV8MemoryAllocatedSize(
576 int index) const {
577 size_t memory_allocated = 0, memory_used = 0;
578 if (!GetV8MemoryUsed(index, &memory_used) ||
579 !GetV8Memory(index, &memory_allocated))
580 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT);
581 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_CACHE_SIZE_CELL_TEXT,
582 ui::FormatBytesWithUnits(memory_allocated,
583 ui::DATA_UNITS_KIBIBYTE,
584 false),
585 ui::FormatBytesWithUnits(memory_used,
586 ui::DATA_UNITS_KIBIBYTE,
587 false));
590 bool TaskManagerModel::GetPrivateMemory(int index, size_t* result) const {
591 *result = 0;
592 base::ProcessHandle handle = GetResource(index)->GetProcess();
593 if (!CachePrivateAndSharedMemory(handle))
594 return false;
595 *result = per_process_cache_[handle].private_bytes;
596 return true;
599 bool TaskManagerModel::GetSharedMemory(int index, size_t* result) const {
600 *result = 0;
601 base::ProcessHandle handle = GetResource(index)->GetProcess();
602 if (!CachePrivateAndSharedMemory(handle))
603 return false;
604 *result = per_process_cache_[handle].shared_bytes;
605 return true;
608 bool TaskManagerModel::GetPhysicalMemory(int index, size_t* result) const {
609 *result = 0;
611 base::ProcessHandle handle = GetResource(index)->GetProcess();
612 PerProcessValues& values(per_process_cache_[handle]);
614 if (!values.is_physical_memory_valid) {
615 base::WorkingSetKBytes ws_usage;
616 MetricsMap::const_iterator iter = metrics_map_.find(handle);
617 if (iter == metrics_map_.end() ||
618 !iter->second->GetWorkingSetKBytes(&ws_usage))
619 return false;
621 values.is_physical_memory_valid = true;
622 #if defined(OS_LINUX)
623 // On Linux private memory is also resident. Just use it.
624 values.physical_memory = ws_usage.priv * 1024;
625 #else
626 // Memory = working_set.private + working_set.shareable.
627 // We exclude the shared memory.
628 values.physical_memory = iter->second->GetWorkingSetSize();
629 values.physical_memory -= ws_usage.shared * 1024;
630 #endif
632 *result = values.physical_memory;
633 return true;
636 void TaskManagerModel::GetGDIHandles(int index,
637 size_t* current,
638 size_t* peak) const {
639 *current = 0;
640 *peak = 0;
641 #if defined(OS_WIN)
642 base::ProcessHandle handle = GetResource(index)->GetProcess();
643 PerProcessValues& values(per_process_cache_[handle]);
645 if (!values.is_gdi_handles_valid) {
646 GetWinGDIHandles(GetResource(index)->GetProcess(),
647 &values.gdi_handles,
648 &values.gdi_handles_peak);
649 values.is_gdi_handles_valid = true;
651 *current = values.gdi_handles;
652 *peak = values.gdi_handles_peak;
653 #endif
656 void TaskManagerModel::GetUSERHandles(int index,
657 size_t* current,
658 size_t* peak) const {
659 *current = 0;
660 *peak = 0;
661 #if defined(OS_WIN)
662 base::ProcessHandle handle = GetResource(index)->GetProcess();
663 PerProcessValues& values(per_process_cache_[handle]);
665 if (!values.is_user_handles_valid) {
666 GetWinUSERHandles(GetResource(index)->GetProcess(),
667 &values.user_handles,
668 &values.user_handles_peak);
669 values.is_user_handles_valid = true;
671 *current = values.user_handles;
672 *peak = values.user_handles_peak;
673 #endif
676 bool TaskManagerModel::GetWebCoreCacheStats(
677 int index,
678 blink::WebCache::ResourceTypeStats* result) const {
679 if (!CacheWebCoreStats(index))
680 return false;
681 *result = GetPerResourceValues(index).webcore_stats;
682 return true;
685 bool TaskManagerModel::GetVideoMemory(int index,
686 size_t* video_memory,
687 bool* has_duplicates) const {
688 *video_memory = 0;
689 *has_duplicates = false;
691 base::ProcessId pid = GetProcessId(index);
692 PerProcessValues& values(
693 per_process_cache_[GetResource(index)->GetProcess()]);
694 if (!values.is_video_memory_valid) {
695 content::GPUVideoMemoryUsageStats::ProcessMap::const_iterator i =
696 video_memory_usage_stats_.process_map.find(pid);
697 if (i == video_memory_usage_stats_.process_map.end())
698 return false;
699 values.is_video_memory_valid = true;
700 values.video_memory = i->second.video_memory;
701 values.video_memory_has_duplicates = i->second.has_duplicates;
703 *video_memory = values.video_memory;
704 *has_duplicates = values.video_memory_has_duplicates;
705 return true;
708 bool TaskManagerModel::GetSqliteMemoryUsedBytes(
709 int index,
710 size_t* result) const {
711 *result = 0;
712 PerResourceValues& values(GetPerResourceValues(index));
713 if (!values.is_sqlite_memory_bytes_valid) {
714 if (!GetResource(index)->ReportsSqliteMemoryUsed())
715 return false;
716 values.is_sqlite_memory_bytes_valid = true;
717 values.sqlite_memory_bytes = GetResource(index)->SqliteMemoryUsedBytes();
719 *result = values.sqlite_memory_bytes;
720 return true;
723 bool TaskManagerModel::GetV8Memory(int index, size_t* result) const {
724 *result = 0;
725 if (!CacheV8Memory(index))
726 return false;
727 *result = GetPerResourceValues(index).v8_memory_allocated;
728 return true;
731 bool TaskManagerModel::GetV8MemoryUsed(int index, size_t* result) const {
732 *result = 0;
733 if (!CacheV8Memory(index))
734 return false;
735 *result = GetPerResourceValues(index).v8_memory_used;
736 return true;
739 bool TaskManagerModel::CanActivate(int index) const {
740 CHECK_LT(index, ResourceCount());
741 return GetResourceWebContents(index) != NULL;
744 bool TaskManagerModel::IsResourceFirstInGroup(int index) const {
745 Resource* resource = GetResource(index);
746 GroupMap::const_iterator iter = group_map_.find(resource->GetProcess());
747 DCHECK(iter != group_map_.end());
748 const ResourceList& group = iter->second;
749 return (group[0] == resource);
752 bool TaskManagerModel::IsResourceLastInGroup(int index) const {
753 Resource* resource = GetResource(index);
754 GroupMap::const_iterator iter = group_map_.find(resource->GetProcess());
755 DCHECK(iter != group_map_.end());
756 const ResourceList& group = iter->second;
757 return (group.back() == resource);
760 gfx::ImageSkia TaskManagerModel::GetResourceIcon(int index) const {
761 gfx::ImageSkia icon = GetResource(index)->GetIcon();
762 if (!icon.isNull())
763 return icon;
765 static const gfx::ImageSkia* default_icon =
766 ResourceBundle::GetSharedInstance().
767 GetNativeImageNamed(IDR_DEFAULT_FAVICON).ToImageSkia();
768 return *default_icon;
771 TaskManagerModel::GroupRange
772 TaskManagerModel::GetGroupRangeForResource(int index) const {
773 Resource* resource = GetResource(index);
774 GroupMap::const_iterator group_iter =
775 group_map_.find(resource->GetProcess());
776 DCHECK(group_iter != group_map_.end());
777 const ResourceList& group = group_iter->second;
778 if (group.size() == 1) {
779 return std::make_pair(index, 1);
780 } else {
781 for (int i = index; i >= 0; --i) {
782 if (GetResource(i) == group[0])
783 return std::make_pair(i, group.size());
785 NOTREACHED();
786 return std::make_pair(-1, -1);
790 int TaskManagerModel::GetGroupIndexForResource(int index) const {
791 int group_index = -1;
792 for (int i = 0; i <= index; ++i) {
793 if (IsResourceFirstInGroup(i))
794 group_index++;
797 DCHECK_NE(group_index, -1);
798 return group_index;
801 int TaskManagerModel::GetResourceIndexForGroup(int group_index,
802 int index_in_group) const {
803 int group_count = -1;
804 int count_in_group = -1;
805 for (int i = 0; i < ResourceCount(); ++i) {
806 if (IsResourceFirstInGroup(i))
807 group_count++;
809 if (group_count == group_index) {
810 count_in_group++;
811 if (count_in_group == index_in_group)
812 return i;
813 } else if (group_count > group_index) {
814 break;
818 NOTREACHED();
819 return -1;
822 int TaskManagerModel::CompareValues(int row1, int row2, int col_id) const {
823 CHECK(row1 < ResourceCount() && row2 < ResourceCount());
824 switch (col_id) {
825 case IDS_TASK_MANAGER_TASK_COLUMN: {
826 static icu::Collator* collator = NULL;
827 if (!collator) {
828 UErrorCode create_status = U_ZERO_ERROR;
829 collator = icu::Collator::createInstance(create_status);
830 if (!U_SUCCESS(create_status)) {
831 collator = NULL;
832 NOTREACHED();
835 const base::string16& title1 = GetResourceTitle(row1);
836 const base::string16& title2 = GetResourceTitle(row2);
837 UErrorCode compare_status = U_ZERO_ERROR;
838 UCollationResult compare_result = collator->compare(
839 static_cast<const UChar*>(title1.c_str()),
840 static_cast<int>(title1.length()),
841 static_cast<const UChar*>(title2.c_str()),
842 static_cast<int>(title2.length()),
843 compare_status);
844 DCHECK(U_SUCCESS(compare_status));
845 return compare_result;
848 case IDS_TASK_MANAGER_PROFILE_NAME_COLUMN: {
849 const base::string16& profile1 = GetResourceProfileName(row1);
850 const base::string16& profile2 = GetResourceProfileName(row2);
851 return profile1.compare(0, profile1.length(), profile2, 0,
852 profile2.length());
855 case IDS_TASK_MANAGER_NET_COLUMN:
856 return ValueCompare(GetNetworkUsage(GetResource(row1)),
857 GetNetworkUsage(GetResource(row2)));
859 case IDS_TASK_MANAGER_CPU_COLUMN:
860 return ValueCompare(GetCPUUsage(GetResource(row1)),
861 GetCPUUsage(GetResource(row2)));
863 case IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN:
864 return ValueCompareMember(
865 this, &TaskManagerModel::GetPrivateMemory, row1, row2);
867 case IDS_TASK_MANAGER_SHARED_MEM_COLUMN:
868 return ValueCompareMember(
869 this, &TaskManagerModel::GetSharedMemory, row1, row2);
871 case IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN:
872 return ValueCompareMember(
873 this, &TaskManagerModel::GetPhysicalMemory, row1, row2);
875 case IDS_TASK_MANAGER_NACL_DEBUG_STUB_PORT_COLUMN:
876 return ValueCompare(GetNaClDebugStubPort(row1),
877 GetNaClDebugStubPort(row2));
879 case IDS_TASK_MANAGER_PROCESS_ID_COLUMN:
880 return ValueCompare(GetProcessId(row1), GetProcessId(row2));
882 case IDS_TASK_MANAGER_GDI_HANDLES_COLUMN: {
883 size_t current1, peak1;
884 size_t current2, peak2;
885 GetGDIHandles(row1, &current1, &peak1);
886 GetGDIHandles(row2, &current2, &peak2);
887 return ValueCompare(current1, current2);
890 case IDS_TASK_MANAGER_USER_HANDLES_COLUMN: {
891 size_t current1, peak1;
892 size_t current2, peak2;
893 GetUSERHandles(row1, &current1, &peak1);
894 GetUSERHandles(row2, &current2, &peak2);
895 return ValueCompare(current1, current2);
898 case IDS_TASK_MANAGER_IDLE_WAKEUPS_COLUMN:
899 return ValueCompare(GetIdleWakeupsPerSecond(row1),
900 GetIdleWakeupsPerSecond(row2));
902 case IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN:
903 case IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN:
904 case IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN: {
905 bool row1_stats_valid = CacheWebCoreStats(row1);
906 bool row2_stats_valid = CacheWebCoreStats(row2);
907 if (row1_stats_valid && row2_stats_valid) {
908 const blink::WebCache::ResourceTypeStats& stats1(
909 GetPerResourceValues(row1).webcore_stats);
910 const blink::WebCache::ResourceTypeStats& stats2(
911 GetPerResourceValues(row2).webcore_stats);
912 switch (col_id) {
913 case IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN:
914 return ValueCompare(stats1.images.size, stats2.images.size);
915 case IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN:
916 return ValueCompare(stats1.scripts.size, stats2.scripts.size);
917 case IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN:
918 return ValueCompare(stats1.cssStyleSheets.size,
919 stats2.cssStyleSheets.size);
920 default:
921 NOTREACHED();
922 return 0;
925 return OrderUnavailableValue(row1_stats_valid, row2_stats_valid);
928 case IDS_TASK_MANAGER_VIDEO_MEMORY_COLUMN: {
929 size_t value1;
930 size_t value2;
931 bool has_duplicates;
932 bool value1_valid = GetVideoMemory(row1, &value1, &has_duplicates);
933 bool value2_valid = GetVideoMemory(row2, &value2, &has_duplicates);
934 return value1_valid && value2_valid ? ValueCompare(value1, value2) :
935 OrderUnavailableValue(value1_valid, value2_valid);
938 case IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN:
939 return ValueCompareMember(
940 this, &TaskManagerModel::GetV8Memory, row1, row2);
942 case IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN:
943 return ValueCompareMember(
944 this, &TaskManagerModel::GetSqliteMemoryUsedBytes, row1, row2);
946 default:
947 NOTREACHED();
948 break;
950 return 0;
953 int TaskManagerModel::GetUniqueChildProcessId(int index) const {
954 return GetResource(index)->GetUniqueChildProcessId();
957 Resource::Type TaskManagerModel::GetResourceType(int index) const {
958 return GetResource(index)->GetType();
961 WebContents* TaskManagerModel::GetResourceWebContents(int index) const {
962 return GetResource(index)->GetWebContents();
965 void TaskManagerModel::AddResource(Resource* resource) {
966 base::ProcessHandle process = resource->GetProcess();
968 GroupMap::iterator group_iter = group_map_.find(process);
969 int new_entry_index = 0;
970 if (group_iter == group_map_.end()) {
971 group_map_.insert(make_pair(process, ResourceList(1, resource)));
973 // Not part of a group, just put at the end of the list.
974 resources_.push_back(resource);
975 new_entry_index = static_cast<int>(resources_.size() - 1);
976 } else {
977 ResourceList* group_entries = &(group_iter->second);
978 group_entries->push_back(resource);
980 // Insert the new entry right after the last entry of its group.
981 ResourceList::iterator iter =
982 std::find(resources_.begin(),
983 resources_.end(),
984 (*group_entries)[group_entries->size() - 2]);
985 DCHECK(iter != resources_.end());
986 new_entry_index = static_cast<int>(iter - resources_.begin()) + 1;
987 resources_.insert(++iter, resource);
990 // Create the ProcessMetrics for this process if needed (not in map).
991 if (metrics_map_.find(process) == metrics_map_.end()) {
992 base::ProcessMetrics* pm =
993 #if !defined(OS_MACOSX)
994 base::ProcessMetrics::CreateProcessMetrics(process);
995 #else
996 base::ProcessMetrics::CreateProcessMetrics(
997 process, content::BrowserChildProcessHost::GetPortProvider());
998 #endif
1000 metrics_map_[process] = pm;
1003 // Notify the table that the contents have changed for it to redraw.
1004 FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_,
1005 OnItemsAdded(new_entry_index, 1));
1008 void TaskManagerModel::RemoveResource(Resource* resource) {
1009 base::ProcessHandle process = resource->GetProcess();
1011 // Find the associated group.
1012 GroupMap::iterator group_iter = group_map_.find(process);
1013 DCHECK(group_iter != group_map_.end());
1014 if (group_iter == group_map_.end())
1015 return;
1016 ResourceList& group_entries = group_iter->second;
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 if (iter != group_entries.end())
1024 group_entries.erase(iter);
1026 // If there are no more entries for that process, do the clean-up.
1027 if (group_entries.empty()) {
1028 group_map_.erase(group_iter);
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);
1039 // Remove the entry from the model list.
1040 iter = std::find(resources_.begin(), resources_.end(), resource);
1041 DCHECK(iter != resources_.end());
1042 if (iter != resources_.end()) {
1043 int index = static_cast<int>(iter - resources_.begin());
1044 // Notify the observers that the contents will change.
1045 FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_,
1046 OnItemsToBeRemoved(index, 1));
1047 // Now actually remove the entry from the model list.
1048 resources_.erase(iter);
1049 // Notify the table that the contents have changed.
1050 FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_,
1051 OnItemsRemoved(index, 1));
1054 // Remove the entry from the network maps.
1055 ResourceValueMap::iterator net_iter =
1056 current_byte_count_map_.find(resource);
1057 if (net_iter != current_byte_count_map_.end())
1058 current_byte_count_map_.erase(net_iter);
1061 void TaskManagerModel::StartUpdating() {
1062 // Multiple StartUpdating requests may come in, and we only need to take
1063 // action the first time.
1064 update_requests_++;
1065 if (update_requests_ > 1)
1066 return;
1067 DCHECK_EQ(1, update_requests_);
1068 DCHECK_NE(TASK_PENDING, update_state_);
1070 // If update_state_ is STOPPING, it means a task is still pending. Setting
1071 // it to TASK_PENDING ensures the tasks keep being posted (by Refresh()).
1072 if (update_state_ == IDLE) {
1073 base::MessageLoop::current()->PostTask(
1074 FROM_HERE,
1075 base::Bind(&TaskManagerModel::RefreshCallback, this));
1077 update_state_ = TASK_PENDING;
1079 // Notify resource providers that we are updating.
1080 StartListening();
1082 if (!resources_.empty()) {
1083 FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_,
1084 OnReadyPeriodicalUpdate());
1087 BrowserThread::PostTask(
1088 BrowserThread::IO, FROM_HERE,
1089 base::Bind(&TaskManagerModel::SetUpdatingByteCount, this, true));
1092 void TaskManagerModel::StopUpdating() {
1093 // Don't actually stop updating until we have heard as many calls as those
1094 // to StartUpdating.
1095 update_requests_--;
1096 if (update_requests_ > 0)
1097 return;
1098 // Make sure that update_requests_ cannot go negative.
1099 CHECK_EQ(0, update_requests_);
1100 DCHECK_EQ(TASK_PENDING, update_state_);
1101 update_state_ = STOPPING;
1103 // Notify resource providers that we are done updating.
1104 StopListening();
1106 BrowserThread::PostTask(
1107 BrowserThread::IO, FROM_HERE,
1108 base::Bind(&TaskManagerModel::SetUpdatingByteCount, this, false));
1111 void TaskManagerModel::StartListening() {
1112 // Multiple StartListening requests may come in and we only need to take
1113 // action the first time.
1114 listen_requests_++;
1115 if (listen_requests_ > 1)
1116 return;
1117 DCHECK_EQ(1, listen_requests_);
1119 // Notify resource providers that we should start listening to events.
1120 for (ResourceProviderList::iterator iter = providers_.begin();
1121 iter != providers_.end(); ++iter) {
1122 (*iter)->StartUpdating();
1126 void TaskManagerModel::StopListening() {
1127 // Don't actually stop listening until we have heard as many calls as those
1128 // to StartListening.
1129 listen_requests_--;
1130 if (listen_requests_ > 0)
1131 return;
1133 DCHECK_EQ(0, listen_requests_);
1135 // Notify resource providers that we are done listening.
1136 for (ResourceProviderList::const_iterator iter = providers_.begin();
1137 iter != providers_.end(); ++iter) {
1138 (*iter)->StopUpdating();
1141 // Must clear the resources before the next attempt to start listening.
1142 Clear();
1145 void TaskManagerModel::Clear() {
1146 int size = ResourceCount();
1147 if (size > 0) {
1148 resources_.clear();
1150 // Clear the groups.
1151 group_map_.clear();
1153 // Clear the process related info.
1154 STLDeleteValues(&metrics_map_);
1156 // Clear the network maps.
1157 current_byte_count_map_.clear();
1159 per_resource_cache_.clear();
1160 per_process_cache_.clear();
1162 FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_,
1163 OnItemsRemoved(0, size));
1167 void TaskManagerModel::ModelChanged() {
1168 // Notify the table that the contents have changed for it to redraw.
1169 FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_, OnModelChanged());
1172 void TaskManagerModel::Refresh() {
1173 per_resource_cache_.clear();
1174 per_process_cache_.clear();
1176 #if !defined(DISABLE_NACL)
1177 nacl::NaClBrowser* nacl_browser = nacl::NaClBrowser::GetInstance();
1178 #endif // !defined(DISABLE_NACL)
1180 // Compute the CPU usage values and check if NaCl GDB debug stub port is
1181 // known.
1182 // Note that we compute the CPU usage for all resources (instead of doing it
1183 // lazily) as process_util::GetCPUUsage() returns the CPU usage since the last
1184 // time it was called, and not calling it everytime would skew the value the
1185 // next time it is retrieved (as it would be for more than 1 cycle).
1186 // The same is true for idle wakeups.
1187 for (ResourceList::iterator iter = resources_.begin();
1188 iter != resources_.end(); ++iter) {
1189 base::ProcessHandle process = (*iter)->GetProcess();
1190 PerProcessValues& values(per_process_cache_[process]);
1191 #if !defined(DISABLE_NACL)
1192 // Debug stub port doesn't change once known.
1193 if (!values.is_nacl_debug_stub_port_valid) {
1194 values.nacl_debug_stub_port = nacl_browser->GetProcessGdbDebugStubPort(
1195 (*iter)->GetUniqueChildProcessId());
1196 if (values.nacl_debug_stub_port != nacl::kGdbDebugStubPortUnknown) {
1197 values.is_nacl_debug_stub_port_valid = true;
1200 #endif // !defined(DISABLE_NACL)
1201 if (values.is_cpu_usage_valid && values.is_idle_wakeups_valid)
1202 continue;
1203 MetricsMap::iterator metrics_iter = metrics_map_.find(process);
1204 DCHECK(metrics_iter != metrics_map_.end());
1205 if (!values.is_cpu_usage_valid) {
1206 values.is_cpu_usage_valid = true;
1207 values.cpu_usage = metrics_iter->second->GetCPUUsage();
1209 #if defined(OS_MACOSX) || defined(OS_LINUX)
1210 // TODO(port): Implement GetIdleWakeupsPerSecond() on other platforms,
1211 // crbug.com/120488
1212 if (!values.is_idle_wakeups_valid) {
1213 values.is_idle_wakeups_valid = true;
1214 values.idle_wakeups = metrics_iter->second->GetIdleWakeupsPerSecond();
1216 #endif // defined(OS_MACOSX) || defined(OS_LINUX)
1219 // Send a request to refresh GPU memory consumption values
1220 RefreshVideoMemoryUsageStats();
1222 // Compute the new network usage values.
1223 base::TimeDelta update_time =
1224 base::TimeDelta::FromMilliseconds(kUpdateTimeMs);
1225 for (ResourceValueMap::iterator iter = current_byte_count_map_.begin();
1226 iter != current_byte_count_map_.end(); ++iter) {
1227 PerResourceValues* values = &(per_resource_cache_[iter->first]);
1228 if (update_time > base::TimeDelta::FromSeconds(1))
1229 values->network_usage = iter->second / update_time.InSeconds();
1230 else
1231 values->network_usage = iter->second * (1 / update_time.InSeconds());
1233 // Then we reset the current byte count.
1234 iter->second = 0;
1237 // Let resources update themselves if they need to.
1238 for (ResourceList::iterator iter = resources_.begin();
1239 iter != resources_.end(); ++iter) {
1240 (*iter)->Refresh();
1243 if (!resources_.empty()) {
1244 FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_,
1245 OnItemsChanged(0, ResourceCount()));
1249 void TaskManagerModel::NotifyResourceTypeStats(
1250 base::ProcessId renderer_id,
1251 const blink::WebCache::ResourceTypeStats& stats) {
1252 for (ResourceList::iterator it = resources_.begin();
1253 it != resources_.end(); ++it) {
1254 if (base::GetProcId((*it)->GetProcess()) == renderer_id) {
1255 (*it)->NotifyResourceTypeStats(stats);
1260 void TaskManagerModel::NotifyVideoMemoryUsageStats(
1261 const content::GPUVideoMemoryUsageStats& video_memory_usage_stats) {
1262 DCHECK(pending_video_memory_usage_stats_update_);
1263 video_memory_usage_stats_ = video_memory_usage_stats;
1264 pending_video_memory_usage_stats_update_ = false;
1267 void TaskManagerModel::NotifyV8HeapStats(base::ProcessId renderer_id,
1268 size_t v8_memory_allocated,
1269 size_t v8_memory_used) {
1270 for (ResourceList::iterator it = resources_.begin();
1271 it != resources_.end(); ++it) {
1272 if (base::GetProcId((*it)->GetProcess()) == renderer_id) {
1273 (*it)->NotifyV8HeapStats(v8_memory_allocated, v8_memory_used);
1278 void TaskManagerModel::NotifyBytesRead(const net::URLRequest& request,
1279 int byte_count) {
1280 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
1281 tracked_objects::ScopedTracker tracking_profile1(
1282 FROM_HERE_WITH_EXPLICIT_FUNCTION(
1283 "423948 TaskManagerModel::NotifyBytesRead1"));
1285 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1286 if (!is_updating_byte_count_)
1287 return;
1289 // Only net::URLRequestJob instances created by the ResourceDispatcherHost
1290 // have an associated ResourceRequestInfo and a render frame associated.
1291 // All other jobs will have -1 returned for the render process child and
1292 // routing ids - the jobs may still match a resource based on their origin id,
1293 // otherwise BytesRead() will attribute the activity to the Browser resource.
1294 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(&request);
1295 int child_id = -1, route_id = -1;
1296 if (info)
1297 info->GetAssociatedRenderFrame(&child_id, &route_id);
1299 // Get the origin PID of the request's originator. This will only be set for
1300 // plugins - for renderer or browser initiated requests it will be zero.
1301 int origin_pid = 0;
1302 if (info)
1303 origin_pid = info->GetOriginPID();
1305 if (bytes_read_buffer_.empty()) {
1306 base::MessageLoop::current()->PostDelayedTask(
1307 FROM_HERE,
1308 base::Bind(&TaskManagerModel::NotifyMultipleBytesRead, this),
1309 base::TimeDelta::FromSeconds(1));
1312 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
1313 tracked_objects::ScopedTracker tracking_profile2(
1314 FROM_HERE_WITH_EXPLICIT_FUNCTION(
1315 "423948 TaskManagerModel::NotifyBytesRead2"));
1317 bytes_read_buffer_.push_back(
1318 BytesReadParam(origin_pid, child_id, route_id, byte_count));
1321 // This is called on the UI thread.
1322 void TaskManagerModel::NotifyDataReady() {
1323 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1324 for (size_t i = 0; i < on_data_ready_callbacks_.size(); ++i) {
1325 if (!on_data_ready_callbacks_[i].is_null())
1326 on_data_ready_callbacks_[i].Run();
1329 on_data_ready_callbacks_.clear();
1332 void TaskManagerModel::RegisterOnDataReadyCallback(
1333 const base::Closure& callback) {
1334 on_data_ready_callbacks_.push_back(callback);
1337 TaskManagerModel::~TaskManagerModel() {
1338 on_data_ready_callbacks_.clear();
1341 void TaskManagerModel::RefreshCallback() {
1342 DCHECK_NE(IDLE, update_state_);
1344 if (update_state_ == STOPPING) {
1345 // We have been asked to stop.
1346 update_state_ = IDLE;
1347 return;
1350 Refresh();
1352 // Schedule the next update.
1353 base::MessageLoop::current()->PostDelayedTask(
1354 FROM_HERE,
1355 base::Bind(&TaskManagerModel::RefreshCallback, this),
1356 base::TimeDelta::FromMilliseconds(kUpdateTimeMs));
1359 void TaskManagerModel::RefreshVideoMemoryUsageStats() {
1360 if (pending_video_memory_usage_stats_update_)
1361 return;
1363 if (!video_memory_usage_stats_observer_.get()) {
1364 video_memory_usage_stats_observer_.reset(
1365 new TaskManagerModelGpuDataManagerObserver());
1367 pending_video_memory_usage_stats_update_ = true;
1368 content::GpuDataManager::GetInstance()->RequestVideoMemoryUsageStatsUpdate();
1371 int64 TaskManagerModel::GetNetworkUsageForResource(Resource* resource) const {
1372 // Returns default of 0 if no network usage.
1373 return per_resource_cache_[resource].network_usage;
1376 void TaskManagerModel::BytesRead(BytesReadParam param) {
1377 if (update_state_ != TASK_PENDING || listen_requests_ == 0) {
1378 // A notification sneaked in while we were stopping the updating, just
1379 // ignore it.
1380 return;
1383 // TODO(jcampan): this should be improved once we have a better way of
1384 // linking a network notification back to the object that initiated it.
1385 Resource* resource = NULL;
1386 for (ResourceProviderList::iterator iter = providers_.begin();
1387 iter != providers_.end(); ++iter) {
1388 resource = (*iter)->GetResource(param.origin_pid,
1389 param.child_id,
1390 param.route_id);
1391 if (resource)
1392 break;
1395 if (resource == NULL) {
1396 // We can't match a resource to the notification. That might mean the
1397 // tab that started a download was closed, or the request may have had
1398 // no originating resource associated with it in the first place.
1399 // We attribute orphaned/unaccounted activity to the Browser process.
1400 CHECK(param.origin_pid || (param.child_id != -1));
1401 param.origin_pid = 0;
1402 param.child_id = param.route_id = -1;
1403 BytesRead(param);
1404 return;
1407 // We do support network usage, mark the resource as such so it can report 0
1408 // instead of N/A.
1409 if (!resource->SupportNetworkUsage())
1410 resource->SetSupportNetworkUsage();
1412 ResourceValueMap::const_iterator iter_res =
1413 current_byte_count_map_.find(resource);
1414 if (iter_res == current_byte_count_map_.end())
1415 current_byte_count_map_[resource] = param.byte_count;
1416 else
1417 current_byte_count_map_[resource] = iter_res->second + param.byte_count;
1420 void TaskManagerModel::MultipleBytesRead(
1421 const std::vector<BytesReadParam>* params) {
1422 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1423 for (std::vector<BytesReadParam>::const_iterator it = params->begin();
1424 it != params->end(); ++it) {
1425 BytesRead(*it);
1429 void TaskManagerModel::NotifyMultipleBytesRead() {
1430 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1431 DCHECK(!bytes_read_buffer_.empty());
1433 std::vector<BytesReadParam>* bytes_read_buffer =
1434 new std::vector<BytesReadParam>;
1435 bytes_read_buffer_.swap(*bytes_read_buffer);
1436 BrowserThread::PostTask(
1437 BrowserThread::UI, FROM_HERE,
1438 base::Bind(&TaskManagerModel::MultipleBytesRead, this,
1439 base::Owned(bytes_read_buffer)));
1442 void TaskManagerModel::SetUpdatingByteCount(bool is_updating) {
1443 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1444 is_updating_byte_count_ = is_updating;
1447 int64 TaskManagerModel::GetNetworkUsage(Resource* resource) const {
1448 int64 net_usage = GetNetworkUsageForResource(resource);
1449 if (net_usage == 0 && !resource->SupportNetworkUsage())
1450 return -1;
1451 return net_usage;
1454 double TaskManagerModel::GetCPUUsage(Resource* resource) const {
1455 const PerProcessValues& values(per_process_cache_[resource->GetProcess()]);
1456 // Returns 0 if not valid, which is fine.
1457 return values.cpu_usage;
1460 int TaskManagerModel::GetIdleWakeupsPerSecond(Resource* resource) const {
1461 const PerProcessValues& values(per_process_cache_[resource->GetProcess()]);
1462 // Returns 0 if not valid, which is fine.
1463 return values.idle_wakeups;
1466 base::string16 TaskManagerModel::GetMemCellText(int64 number) const {
1467 #if !defined(OS_MACOSX)
1468 base::string16 str = base::FormatNumber(number / 1024);
1470 // Adjust number string if necessary.
1471 base::i18n::AdjustStringForLocaleDirection(&str);
1472 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_MEM_CELL_TEXT, str);
1473 #else
1474 // System expectation is to show "100 kB", "200 MB", etc.
1475 // TODO(thakis): Switch to metric units (as opposed to powers of two).
1476 return ui::FormatBytes(number);
1477 #endif
1480 bool TaskManagerModel::CachePrivateAndSharedMemory(
1481 base::ProcessHandle handle) const {
1482 PerProcessValues& values(per_process_cache_[handle]);
1483 if (values.is_private_and_shared_valid)
1484 return true;
1486 MetricsMap::const_iterator iter = metrics_map_.find(handle);
1487 if (iter == metrics_map_.end() ||
1488 !iter->second->GetMemoryBytes(&values.private_bytes,
1489 &values.shared_bytes)) {
1490 return false;
1493 values.is_private_and_shared_valid = true;
1494 return true;
1497 bool TaskManagerModel::CacheWebCoreStats(int index) const {
1498 PerResourceValues& values(GetPerResourceValues(index));
1499 if (!values.is_webcore_stats_valid) {
1500 if (!GetResource(index)->ReportsCacheStats())
1501 return false;
1502 values.is_webcore_stats_valid = true;
1503 values.webcore_stats = GetResource(index)->GetWebCoreCacheStats();
1505 return true;
1508 bool TaskManagerModel::CacheV8Memory(int index) const {
1509 PerResourceValues& values(GetPerResourceValues(index));
1510 if (!values.is_v8_memory_valid) {
1511 if (!GetResource(index)->ReportsV8MemoryStats())
1512 return false;
1513 values.is_v8_memory_valid = true;
1514 values.v8_memory_allocated = GetResource(index)->GetV8MemoryAllocated();
1515 values.v8_memory_used = GetResource(index)->GetV8MemoryUsed();
1517 return true;
1520 void TaskManagerModel::AddResourceProvider(ResourceProvider* provider) {
1521 DCHECK(provider);
1522 providers_.push_back(provider);
1525 TaskManagerModel::PerResourceValues& TaskManagerModel::GetPerResourceValues(
1526 int index) const {
1527 return per_resource_cache_[GetResource(index)];
1530 Resource* TaskManagerModel::GetResource(int index) const {
1531 CHECK_GE(index, 0);
1532 CHECK_LT(index, static_cast<int>(resources_.size()));
1533 return resources_[index];
1536 ////////////////////////////////////////////////////////////////////////////////
1537 // TaskManager class
1538 ////////////////////////////////////////////////////////////////////////////////
1539 // static
1540 void TaskManager::RegisterPrefs(PrefRegistrySimple* registry) {
1541 registry->RegisterDictionaryPref(prefs::kTaskManagerWindowPlacement);
1544 bool TaskManager::IsBrowserProcess(int index) const {
1545 // If some of the selection is out of bounds, ignore. This may happen when
1546 // killing a process that manages several pages.
1547 return index < model_->ResourceCount() &&
1548 model_->GetProcess(index) == base::GetCurrentProcessHandle();
1551 void TaskManager::KillProcess(int index) {
1552 base::ProcessHandle process_handle = model_->GetProcess(index);
1553 DCHECK(process_handle);
1554 if (process_handle != base::GetCurrentProcessHandle()) {
1555 base::Process process =
1556 base::Process::DeprecatedGetProcessFromHandle(process_handle);
1557 process.Terminate(content::RESULT_CODE_KILLED, false);
1561 void TaskManager::ActivateProcess(int index) {
1562 // GetResourceWebContents returns a pointer to the relevant web contents for
1563 // the resource. If the index doesn't correspond to any web contents
1564 // (i.e. refers to the Browser process or a plugin), GetWebContents will
1565 // return NULL.
1566 WebContents* chosen_web_contents = model_->GetResourceWebContents(index);
1567 if (chosen_web_contents && chosen_web_contents->GetDelegate())
1568 chosen_web_contents->GetDelegate()->ActivateContents(chosen_web_contents);
1571 void TaskManager::AddResource(Resource* resource) {
1572 model_->AddResource(resource);
1575 void TaskManager::RemoveResource(Resource* resource) {
1576 model_->RemoveResource(resource);
1579 void TaskManager::OnWindowClosed() {
1580 model_->StopUpdating();
1583 void TaskManager::ModelChanged() {
1584 model_->ModelChanged();
1587 // static
1588 TaskManager* TaskManager::GetInstance() {
1589 return Singleton<TaskManager>::get();
1592 void TaskManager::OpenAboutMemory(chrome::HostDesktopType desktop_type) {
1593 Profile* profile = ProfileManager::GetLastUsedProfileAllowedByPolicy();
1594 if (profile->IsGuestSession() && !g_browser_process->local_state()->
1595 GetBoolean(prefs::kBrowserGuestModeEnabled)) {
1596 UserManager::Show(base::FilePath(),
1597 profiles::USER_MANAGER_NO_TUTORIAL,
1598 profiles::USER_MANAGER_SELECT_PROFILE_CHROME_MEMORY);
1599 return;
1602 chrome::NavigateParams params(
1603 profile, GURL(chrome::kChromeUIMemoryURL), ui::PAGE_TRANSITION_LINK);
1604 params.disposition = NEW_FOREGROUND_TAB;
1605 params.host_desktop_type = desktop_type;
1606 chrome::Navigate(&params);
1609 TaskManager::TaskManager()
1610 : model_(new TaskManagerModel(this)) {
1613 TaskManager::~TaskManager() {