Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / chrome / browser / task_manager / task_manager.cc
blob5107779b4876a926d337fd2a18d9fcb829570564
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/location.h"
11 #include "base/prefs/pref_registry_simple.h"
12 #include "base/prefs/pref_service.h"
13 #include "base/single_thread_task_runner.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 "base/thread_task_runner_handle.h"
20 #include "chrome/browser/browser_process.h"
21 #include "chrome/browser/private_working_set_snapshot.h"
22 #include "chrome/browser/profiles/profile_manager.h"
23 #include "chrome/browser/profiles/profile_window.h"
24 #include "chrome/browser/task_manager/background_information.h"
25 #include "chrome/browser/task_manager/browser_process_resource_provider.h"
26 #include "chrome/browser/task_manager/child_process_resource_provider.h"
27 #include "chrome/browser/task_manager/extension_information.h"
28 #include "chrome/browser/task_manager/guest_information.h"
29 #include "chrome/browser/task_manager/panel_information.h"
30 #include "chrome/browser/task_manager/printing_information.h"
31 #include "chrome/browser/task_manager/resource_provider.h"
32 #include "chrome/browser/task_manager/tab_contents_information.h"
33 #include "chrome/browser/task_manager/web_contents_resource_provider.h"
34 #include "chrome/browser/ui/browser_navigator.h"
35 #include "chrome/browser/ui/user_manager.h"
36 #include "chrome/common/pref_names.h"
37 #include "chrome/common/url_constants.h"
38 #include "chrome/grit/generated_resources.h"
39 #include "components/nacl/browser/nacl_browser.h"
40 #include "content/public/browser/browser_thread.h"
41 #include "content/public/browser/gpu_data_manager.h"
42 #include "content/public/browser/gpu_data_manager_observer.h"
43 #include "content/public/browser/resource_request_info.h"
44 #include "content/public/browser/web_contents.h"
45 #include "content/public/browser/web_contents_delegate.h"
46 #include "content/public/browser/worker_service.h"
47 #include "content/public/common/result_codes.h"
48 #include "extensions/browser/extension_system.h"
49 #include "third_party/icu/source/i18n/unicode/coll.h"
50 #include "ui/base/l10n/l10n_util.h"
51 #include "ui/base/resource/resource_bundle.h"
52 #include "ui/base/text/bytes_formatting.h"
53 #include "ui/gfx/image/image_skia.h"
54 #include "ui/resources/grit/ui_resources.h"
56 #if defined(OS_MACOSX)
57 #include "content/public/browser/browser_child_process_host.h"
58 #endif
60 using content::BrowserThread;
61 using content::ResourceRequestInfo;
62 using content::WebContents;
63 using task_manager::Resource;
64 using task_manager::ResourceProvider;
65 using task_manager::WebContentsInformation;
67 class Profile;
69 namespace {
71 template <class T>
72 int ValueCompare(T value1, T value2) {
73 if (value1 < value2)
74 return -1;
75 if (value1 == value2)
76 return 0;
77 return 1;
80 // Used when one or both of the results to compare are unavailable.
81 int OrderUnavailableValue(bool v1, bool v2) {
82 if (!v1 && !v2)
83 return 0;
84 return v1 ? 1 : -1;
87 // Used by TaskManagerModel::CompareValues(). See it for details of return
88 // value.
89 template <class T>
90 int ValueCompareMember(const TaskManagerModel* model,
91 bool (TaskManagerModel::*f)(int, T*) const,
92 int row1,
93 int row2) {
94 T value1;
95 T value2;
96 bool value1_valid = (model->*f)(row1, &value1);
97 bool value2_valid = (model->*f)(row2, &value2);
98 return value1_valid && value2_valid ? ValueCompare(value1, value2) :
99 OrderUnavailableValue(value1_valid, value2_valid);
102 base::string16 FormatStatsSize(const blink::WebCache::ResourceTypeStat& stat) {
103 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_CACHE_SIZE_CELL_TEXT,
104 ui::FormatBytesWithUnits(stat.size, ui::DATA_UNITS_KIBIBYTE, false),
105 ui::FormatBytesWithUnits(stat.liveSize, ui::DATA_UNITS_KIBIBYTE, false));
108 // Returns true if the specified id should use the first value in the group.
109 bool IsSharedByGroup(int col_id) {
110 switch (col_id) {
111 case IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN:
112 case IDS_TASK_MANAGER_SHARED_MEM_COLUMN:
113 case IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN:
114 case IDS_TASK_MANAGER_CPU_COLUMN:
115 case IDS_TASK_MANAGER_PROCESS_ID_COLUMN:
116 case IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN:
117 case IDS_TASK_MANAGER_VIDEO_MEMORY_COLUMN:
118 case IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN:
119 case IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN:
120 case IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN:
121 case IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN:
122 case IDS_TASK_MANAGER_NACL_DEBUG_STUB_PORT_COLUMN:
123 return true;
124 default:
125 return false;
129 #if defined(OS_WIN)
130 void GetWinGDIHandles(base::ProcessHandle process,
131 size_t* current,
132 size_t* peak) {
133 *current = 0;
134 *peak = 0;
135 // Get a handle to |process| that has PROCESS_QUERY_INFORMATION rights.
136 HANDLE current_process = GetCurrentProcess();
137 HANDLE process_with_query_rights;
138 if (DuplicateHandle(current_process, process, current_process,
139 &process_with_query_rights, PROCESS_QUERY_INFORMATION,
140 false, 0)) {
141 *current = GetGuiResources(process_with_query_rights, GR_GDIOBJECTS);
142 *peak = GetGuiResources(process_with_query_rights, GR_GDIOBJECTS_PEAK);
143 CloseHandle(process_with_query_rights);
147 void GetWinUSERHandles(base::ProcessHandle process,
148 size_t* current,
149 size_t* peak) {
150 *current = 0;
151 *peak = 0;
152 // Get a handle to |process| that has PROCESS_QUERY_INFORMATION rights.
153 HANDLE current_process = GetCurrentProcess();
154 HANDLE process_with_query_rights;
155 if (DuplicateHandle(current_process, process, current_process,
156 &process_with_query_rights, PROCESS_QUERY_INFORMATION,
157 false, 0)) {
158 *current = GetGuiResources(process_with_query_rights, GR_USEROBJECTS);
159 *peak = GetGuiResources(process_with_query_rights, GR_USEROBJECTS_PEAK);
160 CloseHandle(process_with_query_rights);
163 #endif
165 } // namespace
167 class TaskManagerModelGpuDataManagerObserver
168 : public content::GpuDataManagerObserver {
169 public:
170 TaskManagerModelGpuDataManagerObserver() {
171 content::GpuDataManager::GetInstance()->AddObserver(this);
174 ~TaskManagerModelGpuDataManagerObserver() override {
175 content::GpuDataManager::GetInstance()->RemoveObserver(this);
178 static void NotifyVideoMemoryUsageStats(
179 const content::GPUVideoMemoryUsageStats& video_memory_usage_stats) {
180 TaskManager::GetInstance()->model()->NotifyVideoMemoryUsageStats(
181 video_memory_usage_stats);
184 void OnVideoMemoryUsageStatsUpdate(const content::GPUVideoMemoryUsageStats&
185 video_memory_usage_stats) override {
186 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
187 NotifyVideoMemoryUsageStats(video_memory_usage_stats);
188 } else {
189 BrowserThread::PostTask(
190 BrowserThread::UI, FROM_HERE, base::Bind(
191 &TaskManagerModelGpuDataManagerObserver::
192 NotifyVideoMemoryUsageStats,
193 video_memory_usage_stats));
198 TaskManagerModel::PerResourceValues::PerResourceValues()
199 : is_title_valid(false),
200 is_profile_name_valid(false),
201 network_usage(0),
202 is_process_id_valid(false),
203 process_id(0),
204 is_webcore_stats_valid(false),
205 is_sqlite_memory_bytes_valid(false),
206 sqlite_memory_bytes(0),
207 is_v8_memory_valid(false),
208 v8_memory_allocated(0),
209 v8_memory_used(0) {}
211 TaskManagerModel::PerResourceValues::~PerResourceValues() {}
213 TaskManagerModel::PerProcessValues::PerProcessValues()
214 : is_cpu_usage_valid(false),
215 cpu_usage(0),
216 is_idle_wakeups_valid(false),
217 idle_wakeups(0),
218 is_private_and_shared_valid(false),
219 private_bytes(0),
220 shared_bytes(0),
221 is_physical_memory_valid(false),
222 physical_memory(0),
223 is_video_memory_valid(false),
224 video_memory(0),
225 video_memory_has_duplicates(false),
226 is_gdi_handles_valid(false),
227 gdi_handles(0),
228 gdi_handles_peak(0),
229 is_user_handles_valid(0),
230 user_handles(0),
231 user_handles_peak(0),
232 is_nacl_debug_stub_port_valid(false),
233 nacl_debug_stub_port(0) {}
235 TaskManagerModel::PerProcessValues::~PerProcessValues() {}
237 ////////////////////////////////////////////////////////////////////////////////
238 // TaskManagerModel class
239 ////////////////////////////////////////////////////////////////////////////////
241 TaskManagerModel::TaskManagerModel(TaskManager* task_manager)
242 : pending_video_memory_usage_stats_update_(false),
243 update_requests_(0),
244 listen_requests_(0),
245 update_state_(IDLE),
246 is_updating_byte_count_(false) {
247 AddResourceProvider(
248 new task_manager::BrowserProcessResourceProvider(task_manager));
249 AddResourceProvider(new task_manager::WebContentsResourceProvider(
250 task_manager,
251 scoped_ptr<WebContentsInformation>(
252 new task_manager::BackgroundInformation())));
253 AddResourceProvider(new task_manager::WebContentsResourceProvider(
254 task_manager,
255 scoped_ptr<WebContentsInformation>(
256 new task_manager::TabContentsInformation())));
257 #if defined(ENABLE_PRINT_PREVIEW)
258 AddResourceProvider(new task_manager::WebContentsResourceProvider(
259 task_manager,
260 scoped_ptr<WebContentsInformation>(
261 new task_manager::PrintingInformation())));
262 #endif // ENABLE_PRINT_PREVIEW
263 AddResourceProvider(new task_manager::WebContentsResourceProvider(
264 task_manager,
265 scoped_ptr<WebContentsInformation>(
266 new task_manager::PanelInformation())));
267 AddResourceProvider(
268 new task_manager::ChildProcessResourceProvider(task_manager));
269 AddResourceProvider(new task_manager::WebContentsResourceProvider(
270 task_manager,
271 scoped_ptr<WebContentsInformation>(
272 new task_manager::ExtensionInformation())));
273 AddResourceProvider(new task_manager::WebContentsResourceProvider(
274 task_manager,
275 scoped_ptr<WebContentsInformation>(
276 new task_manager::GuestInformation())));
277 #if defined(OS_WIN)
278 working_set_snapshot_.reset(new PrivateWorkingSetSnapshot);
279 working_set_snapshot_->AddToMonitorList("chrome");
280 working_set_snapshot_->AddToMonitorList("nacl64");
281 #endif
284 void TaskManagerModel::AddObserver(TaskManagerModelObserver* observer) {
285 observer_list_.AddObserver(observer);
288 void TaskManagerModel::RemoveObserver(TaskManagerModelObserver* observer) {
289 observer_list_.RemoveObserver(observer);
292 int TaskManagerModel::ResourceCount() const {
293 return resources_.size();
296 int TaskManagerModel::GroupCount() const {
297 return group_map_.size();
300 int TaskManagerModel::GetNaClDebugStubPort(int index) const {
301 base::ProcessHandle handle = GetResource(index)->GetProcess();
302 PerProcessValues& values(per_process_cache_[handle]);
303 if (!values.is_nacl_debug_stub_port_valid) {
304 return nacl::kGdbDebugStubPortUnknown;
306 return values.nacl_debug_stub_port;
309 int64 TaskManagerModel::GetNetworkUsage(int index) const {
310 return GetNetworkUsage(GetResource(index));
313 double TaskManagerModel::GetCPUUsage(int index) const {
314 return GetCPUUsage(GetResource(index));
317 int TaskManagerModel::GetIdleWakeupsPerSecond(int index) const {
318 return GetIdleWakeupsPerSecond(GetResource(index));
321 base::ProcessId TaskManagerModel::GetProcessId(int index) const {
322 PerResourceValues& values(GetPerResourceValues(index));
323 if (!values.is_process_id_valid) {
324 values.is_process_id_valid = true;
325 base::ProcessHandle process(GetResource(index)->GetProcess());
326 DCHECK(process);
327 values.process_id = base::GetProcId(process);
328 DCHECK(values.process_id);
330 return values.process_id;
333 base::ProcessHandle TaskManagerModel::GetProcess(int index) const {
334 return GetResource(index)->GetProcess();
337 base::string16 TaskManagerModel::GetResourceById(int index, int col_id) const {
338 if (IsSharedByGroup(col_id) && !IsResourceFirstInGroup(index))
339 return base::string16();
341 switch (col_id) {
342 case IDS_TASK_MANAGER_TASK_COLUMN:
343 return GetResourceTitle(index);
345 case IDS_TASK_MANAGER_PROFILE_NAME_COLUMN:
346 return GetResourceProfileName(index);
348 case IDS_TASK_MANAGER_NET_COLUMN:
349 return GetResourceNetworkUsage(index);
351 case IDS_TASK_MANAGER_CPU_COLUMN:
352 return GetResourceCPUUsage(index);
354 case IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN:
355 return GetResourcePrivateMemory(index);
357 case IDS_TASK_MANAGER_SHARED_MEM_COLUMN:
358 return GetResourceSharedMemory(index);
360 case IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN:
361 return GetResourcePhysicalMemory(index);
363 case IDS_TASK_MANAGER_PROCESS_ID_COLUMN:
364 return GetResourceProcessId(index);
366 case IDS_TASK_MANAGER_GDI_HANDLES_COLUMN:
367 return GetResourceGDIHandles(index);
369 case IDS_TASK_MANAGER_USER_HANDLES_COLUMN:
370 return GetResourceUSERHandles(index);
372 case IDS_TASK_MANAGER_IDLE_WAKEUPS_COLUMN:
373 return GetResourceIdleWakeupsPerSecond(index);
375 case IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN:
376 return GetResourceWebCoreImageCacheSize(index);
378 case IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN:
379 return GetResourceWebCoreScriptsCacheSize(index);
381 case IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN:
382 return GetResourceWebCoreCSSCacheSize(index);
384 case IDS_TASK_MANAGER_VIDEO_MEMORY_COLUMN:
385 return GetResourceVideoMemory(index);
387 case IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN:
388 return GetResourceSqliteMemoryUsed(index);
390 case IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN:
391 return GetResourceV8MemoryAllocatedSize(index);
393 case IDS_TASK_MANAGER_NACL_DEBUG_STUB_PORT_COLUMN:
394 return GetResourceNaClDebugStubPort(index);
396 default:
397 NOTREACHED();
398 return base::string16();
402 const base::string16& TaskManagerModel::GetResourceTitle(int index) const {
403 PerResourceValues& values = GetPerResourceValues(index);
404 if (!values.is_title_valid) {
405 values.is_title_valid = true;
406 values.title = GetResource(index)->GetTitle();
408 return values.title;
411 const base::string16& TaskManagerModel::GetResourceProfileName(
412 int index) const {
413 PerResourceValues& values(GetPerResourceValues(index));
414 if (!values.is_profile_name_valid) {
415 values.is_profile_name_valid = true;
416 values.profile_name = GetResource(index)->GetProfileName();
418 return values.profile_name;
421 base::string16 TaskManagerModel::GetResourceNaClDebugStubPort(int index) const {
422 int port = GetNaClDebugStubPort(index);
423 if (port == nacl::kGdbDebugStubPortUnknown) {
424 return base::ASCIIToUTF16("Unknown");
425 } else if (port == nacl::kGdbDebugStubPortUnused) {
426 return base::ASCIIToUTF16("N/A");
427 } else {
428 return base::IntToString16(port);
432 base::string16 TaskManagerModel::GetResourceNetworkUsage(int index) const {
433 int64 net_usage = GetNetworkUsage(index);
434 if (net_usage == -1)
435 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT);
436 if (net_usage == 0)
437 return base::ASCIIToUTF16("0");
438 base::string16 net_byte = ui::FormatSpeed(net_usage);
439 // Force number string to have LTR directionality.
440 return base::i18n::GetDisplayStringInLTRDirectionality(net_byte);
443 base::string16 TaskManagerModel::GetResourceCPUUsage(int index) const {
444 return base::UTF8ToUTF16(base::StringPrintf(
445 #if defined(OS_MACOSX)
446 // Activity Monitor shows %cpu with one decimal digit -- be
447 // consistent with that.
448 "%.1f",
449 #else
450 "%.0f",
451 #endif
452 GetCPUUsage(GetResource(index))));
455 base::string16 TaskManagerModel::GetResourcePrivateMemory(int index) const {
456 size_t private_mem;
457 if (!GetPrivateMemory(index, &private_mem))
458 return base::ASCIIToUTF16("N/A");
459 return GetMemCellText(private_mem);
462 base::string16 TaskManagerModel::GetResourceSharedMemory(int index) const {
463 size_t shared_mem;
464 if (!GetSharedMemory(index, &shared_mem))
465 return base::ASCIIToUTF16("N/A");
466 return GetMemCellText(shared_mem);
469 base::string16 TaskManagerModel::GetResourcePhysicalMemory(int index) const {
470 size_t phys_mem;
471 GetPhysicalMemory(index, &phys_mem);
472 return GetMemCellText(phys_mem);
475 base::string16 TaskManagerModel::GetResourceProcessId(int index) const {
476 return base::IntToString16(GetProcessId(index));
479 base::string16 TaskManagerModel::GetResourceGDIHandles(int index) const {
480 size_t current, peak;
481 GetGDIHandles(index, &current, &peak);
482 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_HANDLES_CELL_TEXT,
483 base::IntToString16(current), base::IntToString16(peak));
486 base::string16 TaskManagerModel::GetResourceUSERHandles(int index) const {
487 size_t current, peak;
488 GetUSERHandles(index, &current, &peak);
489 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_HANDLES_CELL_TEXT,
490 base::IntToString16(current), base::IntToString16(peak));
493 base::string16 TaskManagerModel::GetResourceWebCoreImageCacheSize(
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.images);
500 base::string16 TaskManagerModel::GetResourceWebCoreScriptsCacheSize(
501 int index) const {
502 if (!CacheWebCoreStats(index))
503 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT);
504 return FormatStatsSize(GetPerResourceValues(index).webcore_stats.scripts);
507 base::string16 TaskManagerModel::GetResourceWebCoreCSSCacheSize(
508 int index) const {
509 if (!CacheWebCoreStats(index))
510 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT);
511 return FormatStatsSize(
512 GetPerResourceValues(index).webcore_stats.cssStyleSheets);
515 base::string16 TaskManagerModel::GetResourceVideoMemory(int index) const {
516 size_t video_memory;
517 bool has_duplicates;
518 if (!GetVideoMemory(index, &video_memory, &has_duplicates) || !video_memory)
519 return base::ASCIIToUTF16("N/A");
520 if (has_duplicates) {
521 return GetMemCellText(video_memory) + base::ASCIIToUTF16("*");
523 return GetMemCellText(video_memory);
526 base::string16 TaskManagerModel::GetResourceSqliteMemoryUsed(int index) const {
527 size_t bytes = 0;
528 if (!GetSqliteMemoryUsedBytes(index, &bytes))
529 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT);
530 return GetMemCellText(bytes);
533 base::string16 TaskManagerModel::GetResourceIdleWakeupsPerSecond(int index)
534 const {
535 return base::FormatNumber(GetIdleWakeupsPerSecond(GetResource(index)));
538 base::string16 TaskManagerModel::GetResourceV8MemoryAllocatedSize(
539 int index) const {
540 size_t memory_allocated = 0, memory_used = 0;
541 if (!GetV8MemoryUsed(index, &memory_used) ||
542 !GetV8Memory(index, &memory_allocated))
543 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT);
544 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_CACHE_SIZE_CELL_TEXT,
545 ui::FormatBytesWithUnits(memory_allocated,
546 ui::DATA_UNITS_KIBIBYTE,
547 false),
548 ui::FormatBytesWithUnits(memory_used,
549 ui::DATA_UNITS_KIBIBYTE,
550 false));
553 bool TaskManagerModel::GetPrivateMemory(int index, size_t* result) const {
554 *result = 0;
555 base::ProcessHandle handle = GetResource(index)->GetProcess();
556 if (!CachePrivateAndSharedMemory(handle))
557 return false;
558 *result = per_process_cache_[handle].private_bytes;
559 return true;
562 bool TaskManagerModel::GetSharedMemory(int index, size_t* result) const {
563 *result = 0;
564 base::ProcessHandle handle = GetResource(index)->GetProcess();
565 if (!CachePrivateAndSharedMemory(handle))
566 return false;
567 *result = per_process_cache_[handle].shared_bytes;
568 return true;
571 bool TaskManagerModel::GetPhysicalMemory(int index, size_t* result) const {
572 *result = 0;
574 base::ProcessHandle handle = GetResource(index)->GetProcess();
575 PerProcessValues& values(per_process_cache_[handle]);
577 if (!values.is_physical_memory_valid) {
578 base::WorkingSetKBytes ws_usage;
579 MetricsMap::const_iterator iter = metrics_map_.find(handle);
580 if (iter == metrics_map_.end() ||
581 !iter->second->GetWorkingSetKBytes(&ws_usage))
582 return false;
584 values.is_physical_memory_valid = true;
585 #if defined(OS_LINUX)
586 // On Linux private memory is also resident. Just use it.
587 values.physical_memory = ws_usage.priv * 1024;
588 #else
589 // Memory = working_set.private which is working set minus shareable. This
590 // avoids the unpredictable counting that occurs when calculating memory as
591 // working set minus shared (renderer code counted when one tab is open and
592 // not counted when two or more are open) and it is much more efficient to
593 // calculate on Windows.
594 values.physical_memory = iter->second->GetWorkingSetSize();
595 values.physical_memory -= ws_usage.shareable * 1024;
596 #endif
598 *result = values.physical_memory;
599 return true;
602 void TaskManagerModel::GetGDIHandles(int index,
603 size_t* current,
604 size_t* peak) const {
605 *current = 0;
606 *peak = 0;
607 #if defined(OS_WIN)
608 base::ProcessHandle handle = GetResource(index)->GetProcess();
609 PerProcessValues& values(per_process_cache_[handle]);
611 if (!values.is_gdi_handles_valid) {
612 GetWinGDIHandles(GetResource(index)->GetProcess(),
613 &values.gdi_handles,
614 &values.gdi_handles_peak);
615 values.is_gdi_handles_valid = true;
617 *current = values.gdi_handles;
618 *peak = values.gdi_handles_peak;
619 #endif
622 void TaskManagerModel::GetUSERHandles(int index,
623 size_t* current,
624 size_t* peak) const {
625 *current = 0;
626 *peak = 0;
627 #if defined(OS_WIN)
628 base::ProcessHandle handle = GetResource(index)->GetProcess();
629 PerProcessValues& values(per_process_cache_[handle]);
631 if (!values.is_user_handles_valid) {
632 GetWinUSERHandles(GetResource(index)->GetProcess(),
633 &values.user_handles,
634 &values.user_handles_peak);
635 values.is_user_handles_valid = true;
637 *current = values.user_handles;
638 *peak = values.user_handles_peak;
639 #endif
642 bool TaskManagerModel::GetWebCoreCacheStats(
643 int index,
644 blink::WebCache::ResourceTypeStats* result) const {
645 if (!CacheWebCoreStats(index))
646 return false;
647 *result = GetPerResourceValues(index).webcore_stats;
648 return true;
651 bool TaskManagerModel::GetVideoMemory(int index,
652 size_t* video_memory,
653 bool* has_duplicates) const {
654 *video_memory = 0;
655 *has_duplicates = false;
657 base::ProcessId pid = GetProcessId(index);
658 PerProcessValues& values(
659 per_process_cache_[GetResource(index)->GetProcess()]);
660 if (!values.is_video_memory_valid) {
661 content::GPUVideoMemoryUsageStats::ProcessMap::const_iterator i =
662 video_memory_usage_stats_.process_map.find(pid);
663 if (i == video_memory_usage_stats_.process_map.end())
664 return false;
665 values.is_video_memory_valid = true;
666 values.video_memory = i->second.video_memory;
667 values.video_memory_has_duplicates = i->second.has_duplicates;
669 *video_memory = values.video_memory;
670 *has_duplicates = values.video_memory_has_duplicates;
671 return true;
674 bool TaskManagerModel::GetSqliteMemoryUsedBytes(
675 int index,
676 size_t* result) const {
677 *result = 0;
678 PerResourceValues& values(GetPerResourceValues(index));
679 if (!values.is_sqlite_memory_bytes_valid) {
680 if (!GetResource(index)->ReportsSqliteMemoryUsed())
681 return false;
682 values.is_sqlite_memory_bytes_valid = true;
683 values.sqlite_memory_bytes = GetResource(index)->SqliteMemoryUsedBytes();
685 *result = values.sqlite_memory_bytes;
686 return true;
689 bool TaskManagerModel::GetV8Memory(int index, size_t* result) const {
690 *result = 0;
691 if (!CacheV8Memory(index))
692 return false;
693 *result = GetPerResourceValues(index).v8_memory_allocated;
694 return true;
697 bool TaskManagerModel::GetV8MemoryUsed(int index, size_t* result) const {
698 *result = 0;
699 if (!CacheV8Memory(index))
700 return false;
701 *result = GetPerResourceValues(index).v8_memory_used;
702 return true;
705 bool TaskManagerModel::CanActivate(int index) const {
706 CHECK_LT(index, ResourceCount());
707 return GetResourceWebContents(index) != NULL;
710 bool TaskManagerModel::IsResourceFirstInGroup(int index) const {
711 Resource* resource = GetResource(index);
712 GroupMap::const_iterator iter = group_map_.find(resource->GetProcess());
713 DCHECK(iter != group_map_.end());
714 const ResourceList& group = iter->second;
715 return (group[0] == resource);
718 bool TaskManagerModel::IsResourceLastInGroup(int index) const {
719 Resource* resource = GetResource(index);
720 GroupMap::const_iterator iter = group_map_.find(resource->GetProcess());
721 DCHECK(iter != group_map_.end());
722 const ResourceList& group = iter->second;
723 return (group.back() == resource);
726 gfx::ImageSkia TaskManagerModel::GetResourceIcon(int index) const {
727 gfx::ImageSkia icon = GetResource(index)->GetIcon();
728 if (!icon.isNull())
729 return icon;
731 static const gfx::ImageSkia* default_icon =
732 ResourceBundle::GetSharedInstance().
733 GetNativeImageNamed(IDR_DEFAULT_FAVICON).ToImageSkia();
734 return *default_icon;
737 TaskManagerModel::GroupRange
738 TaskManagerModel::GetGroupRangeForResource(int index) const {
739 Resource* resource = GetResource(index);
740 GroupMap::const_iterator group_iter =
741 group_map_.find(resource->GetProcess());
742 DCHECK(group_iter != group_map_.end());
743 const ResourceList& group = group_iter->second;
744 if (group.size() == 1) {
745 return std::make_pair(index, 1);
746 } else {
747 for (int i = index; i >= 0; --i) {
748 if (GetResource(i) == group[0])
749 return std::make_pair(i, group.size());
751 NOTREACHED();
752 return std::make_pair(-1, -1);
756 int TaskManagerModel::GetGroupIndexForResource(int index) const {
757 int group_index = -1;
758 for (int i = 0; i <= index; ++i) {
759 if (IsResourceFirstInGroup(i))
760 group_index++;
763 DCHECK_NE(group_index, -1);
764 return group_index;
767 int TaskManagerModel::GetResourceIndexForGroup(int group_index,
768 int index_in_group) const {
769 int group_count = -1;
770 int count_in_group = -1;
771 for (int i = 0; i < ResourceCount(); ++i) {
772 if (IsResourceFirstInGroup(i))
773 group_count++;
775 if (group_count == group_index) {
776 count_in_group++;
777 if (count_in_group == index_in_group)
778 return i;
779 } else if (group_count > group_index) {
780 break;
784 NOTREACHED();
785 return -1;
788 int TaskManagerModel::CompareValues(int row1, int row2, int col_id) const {
789 CHECK(row1 < ResourceCount() && row2 < ResourceCount());
790 switch (col_id) {
791 case IDS_TASK_MANAGER_TASK_COLUMN: {
792 static icu::Collator* collator = NULL;
793 if (!collator) {
794 UErrorCode create_status = U_ZERO_ERROR;
795 collator = icu::Collator::createInstance(create_status);
796 if (!U_SUCCESS(create_status)) {
797 collator = NULL;
798 NOTREACHED();
801 const base::string16& title1 = GetResourceTitle(row1);
802 const base::string16& title2 = GetResourceTitle(row2);
803 UErrorCode compare_status = U_ZERO_ERROR;
804 UCollationResult compare_result = collator->compare(
805 static_cast<const UChar*>(title1.c_str()),
806 static_cast<int>(title1.length()),
807 static_cast<const UChar*>(title2.c_str()),
808 static_cast<int>(title2.length()),
809 compare_status);
810 DCHECK(U_SUCCESS(compare_status));
811 return compare_result;
814 case IDS_TASK_MANAGER_PROFILE_NAME_COLUMN: {
815 const base::string16& profile1 = GetResourceProfileName(row1);
816 const base::string16& profile2 = GetResourceProfileName(row2);
817 return profile1.compare(0, profile1.length(), profile2, 0,
818 profile2.length());
821 case IDS_TASK_MANAGER_NET_COLUMN:
822 return ValueCompare(GetNetworkUsage(GetResource(row1)),
823 GetNetworkUsage(GetResource(row2)));
825 case IDS_TASK_MANAGER_CPU_COLUMN:
826 return ValueCompare(GetCPUUsage(GetResource(row1)),
827 GetCPUUsage(GetResource(row2)));
829 case IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN:
830 return ValueCompareMember(
831 this, &TaskManagerModel::GetPrivateMemory, row1, row2);
833 case IDS_TASK_MANAGER_SHARED_MEM_COLUMN:
834 return ValueCompareMember(
835 this, &TaskManagerModel::GetSharedMemory, row1, row2);
837 case IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN:
838 return ValueCompareMember(
839 this, &TaskManagerModel::GetPhysicalMemory, row1, row2);
841 case IDS_TASK_MANAGER_NACL_DEBUG_STUB_PORT_COLUMN:
842 return ValueCompare(GetNaClDebugStubPort(row1),
843 GetNaClDebugStubPort(row2));
845 case IDS_TASK_MANAGER_PROCESS_ID_COLUMN:
846 return ValueCompare(GetProcessId(row1), GetProcessId(row2));
848 case IDS_TASK_MANAGER_GDI_HANDLES_COLUMN: {
849 size_t current1, peak1;
850 size_t current2, peak2;
851 GetGDIHandles(row1, &current1, &peak1);
852 GetGDIHandles(row2, &current2, &peak2);
853 return ValueCompare(current1, current2);
856 case IDS_TASK_MANAGER_USER_HANDLES_COLUMN: {
857 size_t current1, peak1;
858 size_t current2, peak2;
859 GetUSERHandles(row1, &current1, &peak1);
860 GetUSERHandles(row2, &current2, &peak2);
861 return ValueCompare(current1, current2);
864 case IDS_TASK_MANAGER_IDLE_WAKEUPS_COLUMN:
865 return ValueCompare(GetIdleWakeupsPerSecond(row1),
866 GetIdleWakeupsPerSecond(row2));
868 case IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN:
869 case IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN:
870 case IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN: {
871 bool row1_stats_valid = CacheWebCoreStats(row1);
872 bool row2_stats_valid = CacheWebCoreStats(row2);
873 if (row1_stats_valid && row2_stats_valid) {
874 const blink::WebCache::ResourceTypeStats& stats1(
875 GetPerResourceValues(row1).webcore_stats);
876 const blink::WebCache::ResourceTypeStats& stats2(
877 GetPerResourceValues(row2).webcore_stats);
878 switch (col_id) {
879 case IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN:
880 return ValueCompare(stats1.images.size, stats2.images.size);
881 case IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN:
882 return ValueCompare(stats1.scripts.size, stats2.scripts.size);
883 case IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN:
884 return ValueCompare(stats1.cssStyleSheets.size,
885 stats2.cssStyleSheets.size);
886 default:
887 NOTREACHED();
888 return 0;
891 return OrderUnavailableValue(row1_stats_valid, row2_stats_valid);
894 case IDS_TASK_MANAGER_VIDEO_MEMORY_COLUMN: {
895 size_t value1;
896 size_t value2;
897 bool has_duplicates;
898 bool value1_valid = GetVideoMemory(row1, &value1, &has_duplicates);
899 bool value2_valid = GetVideoMemory(row2, &value2, &has_duplicates);
900 return value1_valid && value2_valid ? ValueCompare(value1, value2) :
901 OrderUnavailableValue(value1_valid, value2_valid);
904 case IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN:
905 return ValueCompareMember(
906 this, &TaskManagerModel::GetV8Memory, row1, row2);
908 case IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN:
909 return ValueCompareMember(
910 this, &TaskManagerModel::GetSqliteMemoryUsedBytes, row1, row2);
912 default:
913 NOTREACHED();
914 break;
916 return 0;
919 int TaskManagerModel::GetUniqueChildProcessId(int index) const {
920 return GetResource(index)->GetUniqueChildProcessId();
923 Resource::Type TaskManagerModel::GetResourceType(int index) const {
924 return GetResource(index)->GetType();
927 WebContents* TaskManagerModel::GetResourceWebContents(int index) const {
928 return GetResource(index)->GetWebContents();
931 void TaskManagerModel::AddResource(Resource* resource) {
932 base::ProcessHandle process = resource->GetProcess();
933 DCHECK(process);
935 GroupMap::iterator group_iter = group_map_.find(process);
936 int new_entry_index = 0;
937 if (group_iter == group_map_.end()) {
938 group_map_.insert(make_pair(process, ResourceList(1, resource)));
940 // Not part of a group, just put at the end of the list.
941 resources_.push_back(resource);
942 new_entry_index = static_cast<int>(resources_.size() - 1);
943 } else {
944 ResourceList* group_entries = &(group_iter->second);
945 group_entries->push_back(resource);
947 // Insert the new entry right after the last entry of its group.
948 ResourceList::iterator iter =
949 std::find(resources_.begin(),
950 resources_.end(),
951 (*group_entries)[group_entries->size() - 2]);
952 DCHECK(iter != resources_.end());
953 new_entry_index = static_cast<int>(iter - resources_.begin()) + 1;
954 resources_.insert(++iter, resource);
957 // Create the ProcessMetrics for this process if needed (not in map).
958 if (metrics_map_.find(process) == metrics_map_.end()) {
959 base::ProcessMetrics* pm =
960 #if !defined(OS_MACOSX)
961 base::ProcessMetrics::CreateProcessMetrics(process);
962 #else
963 base::ProcessMetrics::CreateProcessMetrics(
964 process, content::BrowserChildProcessHost::GetPortProvider());
965 #endif
967 metrics_map_[process] = pm;
970 // Notify the table that the contents have changed for it to redraw.
971 FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_,
972 OnItemsAdded(new_entry_index, 1));
975 void TaskManagerModel::RemoveResource(Resource* resource) {
976 base::ProcessHandle process = resource->GetProcess();
978 // Find the associated group.
979 GroupMap::iterator group_iter = group_map_.find(process);
980 DCHECK(group_iter != group_map_.end());
981 if (group_iter == group_map_.end())
982 return;
983 ResourceList& group_entries = group_iter->second;
985 // Remove the entry from the group map.
986 ResourceList::iterator iter = std::find(group_entries.begin(),
987 group_entries.end(),
988 resource);
989 DCHECK(iter != group_entries.end());
990 if (iter != group_entries.end())
991 group_entries.erase(iter);
993 // If there are no more entries for that process, do the clean-up.
994 if (group_entries.empty()) {
995 group_map_.erase(group_iter);
997 // Nobody is using this process, we don't need the process metrics anymore.
998 MetricsMap::iterator pm_iter = metrics_map_.find(process);
999 DCHECK(pm_iter != metrics_map_.end());
1000 if (pm_iter != metrics_map_.end()) {
1001 delete pm_iter->second;
1002 metrics_map_.erase(process);
1006 // Remove the entry from the model list.
1007 iter = std::find(resources_.begin(), resources_.end(), resource);
1008 DCHECK(iter != resources_.end());
1009 if (iter != resources_.end()) {
1010 int index = static_cast<int>(iter - resources_.begin());
1011 // Notify the observers that the contents will change.
1012 FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_,
1013 OnItemsToBeRemoved(index, 1));
1014 // Now actually remove the entry from the model list.
1015 resources_.erase(iter);
1016 // Notify the table that the contents have changed.
1017 FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_,
1018 OnItemsRemoved(index, 1));
1021 // Remove the entry from the network maps.
1022 ResourceValueMap::iterator net_iter =
1023 current_byte_count_map_.find(resource);
1024 if (net_iter != current_byte_count_map_.end())
1025 current_byte_count_map_.erase(net_iter);
1028 void TaskManagerModel::StartUpdating() {
1029 // Multiple StartUpdating requests may come in, and we only need to take
1030 // action the first time.
1031 update_requests_++;
1032 if (update_requests_ > 1)
1033 return;
1034 DCHECK_EQ(1, update_requests_);
1035 DCHECK_NE(TASK_PENDING, update_state_);
1037 // If update_state_ is STOPPING, it means a task is still pending. Setting
1038 // it to TASK_PENDING ensures the tasks keep being posted (by Refresh()).
1039 if (update_state_ == IDLE) {
1040 base::ThreadTaskRunnerHandle::Get()->PostTask(
1041 FROM_HERE, base::Bind(&TaskManagerModel::RefreshCallback, this));
1043 update_state_ = TASK_PENDING;
1045 // Notify resource providers that we are updating.
1046 StartListening();
1048 if (!resources_.empty()) {
1049 FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_,
1050 OnReadyPeriodicalUpdate());
1053 BrowserThread::PostTask(
1054 BrowserThread::IO, FROM_HERE,
1055 base::Bind(&TaskManagerModel::SetUpdatingByteCount, this, true));
1058 void TaskManagerModel::StopUpdating() {
1059 // Don't actually stop updating until we have heard as many calls as those
1060 // to StartUpdating.
1061 update_requests_--;
1062 if (update_requests_ > 0)
1063 return;
1064 // Make sure that update_requests_ cannot go negative.
1065 CHECK_EQ(0, update_requests_);
1066 DCHECK_EQ(TASK_PENDING, update_state_);
1067 update_state_ = STOPPING;
1069 // Notify resource providers that we are done updating.
1070 StopListening();
1072 BrowserThread::PostTask(
1073 BrowserThread::IO, FROM_HERE,
1074 base::Bind(&TaskManagerModel::SetUpdatingByteCount, this, false));
1077 void TaskManagerModel::StartListening() {
1078 // Multiple StartListening requests may come in and we only need to take
1079 // action the first time.
1080 listen_requests_++;
1081 if (listen_requests_ > 1)
1082 return;
1083 DCHECK_EQ(1, listen_requests_);
1085 // Notify resource providers that we should start listening to events.
1086 for (ResourceProviderList::iterator iter = providers_.begin();
1087 iter != providers_.end(); ++iter) {
1088 (*iter)->StartUpdating();
1092 void TaskManagerModel::StopListening() {
1093 // Don't actually stop listening until we have heard as many calls as those
1094 // to StartListening.
1095 listen_requests_--;
1096 if (listen_requests_ > 0)
1097 return;
1099 DCHECK_EQ(0, listen_requests_);
1101 // Notify resource providers that we are done listening.
1102 for (ResourceProviderList::const_iterator iter = providers_.begin();
1103 iter != providers_.end(); ++iter) {
1104 (*iter)->StopUpdating();
1107 // Must clear the resources before the next attempt to start listening.
1108 Clear();
1111 void TaskManagerModel::Clear() {
1112 int size = ResourceCount();
1113 if (size > 0) {
1114 resources_.clear();
1116 // Clear the groups.
1117 group_map_.clear();
1119 // Clear the process related info.
1120 STLDeleteValues(&metrics_map_);
1122 // Clear the network maps.
1123 current_byte_count_map_.clear();
1125 per_resource_cache_.clear();
1126 per_process_cache_.clear();
1128 FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_,
1129 OnItemsRemoved(0, size));
1133 void TaskManagerModel::ModelChanged() {
1134 // Notify the table that the contents have changed for it to redraw.
1135 FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_, OnModelChanged());
1138 void TaskManagerModel::RefreshPhysicalMemoryFromWorkingSetSnapshot() {
1139 #if defined(OS_WIN)
1140 // Collect working-set data for all monitored processes in one operation, to
1141 // avoid the inefficiency of retrieving it one at a time.
1142 working_set_snapshot_->Sample();
1144 for (size_t i = 0; i < resources_.size(); ++i) {
1145 size_t private_working_set =
1146 working_set_snapshot_->GetPrivateWorkingSet(GetProcessId(i));
1148 // If working-set data is available then use it. If not then
1149 // GetWorkingSetKBytes will retrieve the data. This is rare except on
1150 // Windows XP where GetWorkingSetKBytes will always be used.
1151 if (private_working_set) {
1152 // Fill in the cache with the retrieved private working set value.
1153 base::ProcessHandle handle = GetResource(i)->GetProcess();
1154 PerProcessValues& values(per_process_cache_[handle]);
1155 values.is_physical_memory_valid = true;
1156 // Note that the other memory fields are *not* filled in.
1157 values.physical_memory = private_working_set;
1160 #else
1161 // This is a NOP on other platforms because they can efficiently retrieve
1162 // the private working-set data on a per-process basis.
1163 #endif
1166 void TaskManagerModel::Refresh() {
1167 per_resource_cache_.clear();
1168 per_process_cache_.clear();
1169 RefreshPhysicalMemoryFromWorkingSetSnapshot();
1171 #if !defined(DISABLE_NACL)
1172 nacl::NaClBrowser* nacl_browser = nacl::NaClBrowser::GetInstance();
1173 #endif // !defined(DISABLE_NACL)
1175 // Compute the CPU usage values and check if NaCl GDB debug stub port is
1176 // known.
1177 // Note that we compute the CPU usage for all resources (instead of doing it
1178 // lazily) as process_util::GetCPUUsage() returns the CPU usage since the last
1179 // time it was called, and not calling it everytime would skew the value the
1180 // next time it is retrieved (as it would be for more than 1 cycle).
1181 // The same is true for idle wakeups.
1182 for (ResourceList::iterator iter = resources_.begin();
1183 iter != resources_.end(); ++iter) {
1184 base::ProcessHandle process = (*iter)->GetProcess();
1185 PerProcessValues& values(per_process_cache_[process]);
1186 #if !defined(DISABLE_NACL)
1187 // Debug stub port doesn't change once known.
1188 if (!values.is_nacl_debug_stub_port_valid) {
1189 values.nacl_debug_stub_port = nacl_browser->GetProcessGdbDebugStubPort(
1190 (*iter)->GetUniqueChildProcessId());
1191 if (values.nacl_debug_stub_port != nacl::kGdbDebugStubPortUnknown) {
1192 values.is_nacl_debug_stub_port_valid = true;
1195 #endif // !defined(DISABLE_NACL)
1196 if (values.is_cpu_usage_valid && values.is_idle_wakeups_valid)
1197 continue;
1198 MetricsMap::iterator metrics_iter = metrics_map_.find(process);
1199 DCHECK(metrics_iter != metrics_map_.end());
1200 if (!values.is_cpu_usage_valid) {
1201 values.is_cpu_usage_valid = true;
1202 values.cpu_usage = metrics_iter->second->GetCPUUsage();
1204 #if defined(OS_MACOSX) || defined(OS_LINUX)
1205 // TODO(port): Implement GetIdleWakeupsPerSecond() on other platforms,
1206 // crbug.com/120488
1207 if (!values.is_idle_wakeups_valid) {
1208 values.is_idle_wakeups_valid = true;
1209 values.idle_wakeups = metrics_iter->second->GetIdleWakeupsPerSecond();
1211 #endif // defined(OS_MACOSX) || defined(OS_LINUX)
1214 // Send a request to refresh GPU memory consumption values
1215 RefreshVideoMemoryUsageStats();
1217 // Compute the new network usage values.
1218 base::TimeDelta update_time =
1219 base::TimeDelta::FromMilliseconds(kUpdateTimeMs);
1220 for (ResourceValueMap::iterator iter = current_byte_count_map_.begin();
1221 iter != current_byte_count_map_.end(); ++iter) {
1222 PerResourceValues* values = &(per_resource_cache_[iter->first]);
1223 if (update_time > base::TimeDelta::FromSeconds(1))
1224 values->network_usage = iter->second / update_time.InSeconds();
1225 else
1226 values->network_usage = iter->second * (1 / update_time.InSeconds());
1228 // Then we reset the current byte count.
1229 iter->second = 0;
1232 // Let resources update themselves if they need to.
1233 for (ResourceList::iterator iter = resources_.begin();
1234 iter != resources_.end(); ++iter) {
1235 (*iter)->Refresh();
1238 if (!resources_.empty()) {
1239 FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_,
1240 OnItemsChanged(0, ResourceCount()));
1244 void TaskManagerModel::NotifyVideoMemoryUsageStats(
1245 const content::GPUVideoMemoryUsageStats& video_memory_usage_stats) {
1246 DCHECK(pending_video_memory_usage_stats_update_);
1247 video_memory_usage_stats_ = video_memory_usage_stats;
1248 pending_video_memory_usage_stats_update_ = false;
1251 void TaskManagerModel::NotifyBytesRead(const net::URLRequest& request,
1252 int byte_count) {
1253 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1254 if (!is_updating_byte_count_)
1255 return;
1257 // Only net::URLRequestJob instances created by the ResourceDispatcherHost
1258 // have an associated ResourceRequestInfo and a render frame associated.
1259 // All other jobs will have -1 returned for the render process child and
1260 // routing ids - the jobs may still match a resource based on their origin id,
1261 // otherwise BytesRead() will attribute the activity to the Browser resource.
1262 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(&request);
1263 int child_id = -1, route_id = -1;
1264 if (info)
1265 info->GetAssociatedRenderFrame(&child_id, &route_id);
1267 // Get the origin PID of the request's originator. This will only be set for
1268 // plugins - for renderer or browser initiated requests it will be zero.
1269 int origin_pid = 0;
1270 if (info)
1271 origin_pid = info->GetOriginPID();
1273 if (bytes_read_buffer_.empty()) {
1274 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
1275 FROM_HERE, base::Bind(&TaskManagerModel::NotifyMultipleBytesRead, this),
1276 base::TimeDelta::FromSeconds(1));
1279 bytes_read_buffer_.push_back(
1280 BytesReadParam(origin_pid, child_id, route_id, byte_count));
1283 // This is called on the UI thread.
1284 void TaskManagerModel::NotifyDataReady() {
1285 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1286 for (size_t i = 0; i < on_data_ready_callbacks_.size(); ++i) {
1287 if (!on_data_ready_callbacks_[i].is_null())
1288 on_data_ready_callbacks_[i].Run();
1291 on_data_ready_callbacks_.clear();
1294 void TaskManagerModel::RegisterOnDataReadyCallback(
1295 const base::Closure& callback) {
1296 on_data_ready_callbacks_.push_back(callback);
1299 TaskManagerModel::~TaskManagerModel() {
1300 on_data_ready_callbacks_.clear();
1303 void TaskManagerModel::RefreshCallback() {
1304 DCHECK_NE(IDLE, update_state_);
1306 if (update_state_ == STOPPING) {
1307 // We have been asked to stop.
1308 update_state_ = IDLE;
1309 return;
1312 Refresh();
1314 // Schedule the next update.
1315 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
1316 FROM_HERE, base::Bind(&TaskManagerModel::RefreshCallback, this),
1317 base::TimeDelta::FromMilliseconds(kUpdateTimeMs));
1320 void TaskManagerModel::RefreshVideoMemoryUsageStats() {
1321 if (pending_video_memory_usage_stats_update_)
1322 return;
1324 if (!video_memory_usage_stats_observer_.get()) {
1325 video_memory_usage_stats_observer_.reset(
1326 new TaskManagerModelGpuDataManagerObserver());
1328 pending_video_memory_usage_stats_update_ = true;
1329 content::GpuDataManager::GetInstance()->RequestVideoMemoryUsageStatsUpdate();
1332 int64 TaskManagerModel::GetNetworkUsageForResource(Resource* resource) const {
1333 // Returns default of 0 if no network usage.
1334 return per_resource_cache_[resource].network_usage;
1337 void TaskManagerModel::BytesRead(BytesReadParam param) {
1338 if (update_state_ != TASK_PENDING || listen_requests_ == 0) {
1339 // A notification sneaked in while we were stopping the updating, just
1340 // ignore it.
1341 return;
1344 // TODO(jcampan): this should be improved once we have a better way of
1345 // linking a network notification back to the object that initiated it.
1346 Resource* resource = NULL;
1347 for (ResourceProviderList::iterator iter = providers_.begin();
1348 iter != providers_.end(); ++iter) {
1349 resource = (*iter)->GetResource(param.origin_pid,
1350 param.child_id,
1351 param.route_id);
1352 if (resource)
1353 break;
1356 if (resource == NULL) {
1357 // We can't match a resource to the notification. That might mean the
1358 // tab that started a download was closed, or the request may have had
1359 // no originating resource associated with it in the first place.
1360 // We attribute orphaned/unaccounted activity to the Browser process.
1361 CHECK(param.origin_pid || (param.child_id != -1));
1362 param.origin_pid = 0;
1363 param.child_id = param.route_id = -1;
1364 BytesRead(param);
1365 return;
1368 // We do support network usage, mark the resource as such so it can report 0
1369 // instead of N/A.
1370 if (!resource->SupportNetworkUsage())
1371 resource->SetSupportNetworkUsage();
1373 ResourceValueMap::const_iterator iter_res =
1374 current_byte_count_map_.find(resource);
1375 if (iter_res == current_byte_count_map_.end())
1376 current_byte_count_map_[resource] = param.byte_count;
1377 else
1378 current_byte_count_map_[resource] = iter_res->second + param.byte_count;
1381 void TaskManagerModel::MultipleBytesRead(
1382 const std::vector<BytesReadParam>* params) {
1383 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1384 for (std::vector<BytesReadParam>::const_iterator it = params->begin();
1385 it != params->end(); ++it) {
1386 BytesRead(*it);
1390 void TaskManagerModel::NotifyMultipleBytesRead() {
1391 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1392 DCHECK(!bytes_read_buffer_.empty());
1394 std::vector<BytesReadParam>* bytes_read_buffer =
1395 new std::vector<BytesReadParam>;
1396 bytes_read_buffer_.swap(*bytes_read_buffer);
1397 BrowserThread::PostTask(
1398 BrowserThread::UI, FROM_HERE,
1399 base::Bind(&TaskManagerModel::MultipleBytesRead, this,
1400 base::Owned(bytes_read_buffer)));
1403 void TaskManagerModel::SetUpdatingByteCount(bool is_updating) {
1404 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1405 is_updating_byte_count_ = is_updating;
1408 int64 TaskManagerModel::GetNetworkUsage(Resource* resource) const {
1409 int64 net_usage = GetNetworkUsageForResource(resource);
1410 if (net_usage == 0 && !resource->SupportNetworkUsage())
1411 return -1;
1412 return net_usage;
1415 double TaskManagerModel::GetCPUUsage(Resource* resource) const {
1416 const PerProcessValues& values(per_process_cache_[resource->GetProcess()]);
1417 // Returns 0 if not valid, which is fine.
1418 return values.cpu_usage;
1421 int TaskManagerModel::GetIdleWakeupsPerSecond(Resource* resource) const {
1422 const PerProcessValues& values(per_process_cache_[resource->GetProcess()]);
1423 // Returns 0 if not valid, which is fine.
1424 return values.idle_wakeups;
1427 base::string16 TaskManagerModel::GetMemCellText(int64 number) const {
1428 #if !defined(OS_MACOSX)
1429 base::string16 str = base::FormatNumber(number / 1024);
1431 // Adjust number string if necessary.
1432 base::i18n::AdjustStringForLocaleDirection(&str);
1433 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_MEM_CELL_TEXT, str);
1434 #else
1435 // System expectation is to show "100 kB", "200 MB", etc.
1436 // TODO(thakis): Switch to metric units (as opposed to powers of two).
1437 return ui::FormatBytes(number);
1438 #endif
1441 bool TaskManagerModel::CachePrivateAndSharedMemory(
1442 base::ProcessHandle handle) const {
1443 PerProcessValues& values(per_process_cache_[handle]);
1444 if (values.is_private_and_shared_valid)
1445 return true;
1447 MetricsMap::const_iterator iter = metrics_map_.find(handle);
1448 if (iter == metrics_map_.end() ||
1449 !iter->second->GetMemoryBytes(&values.private_bytes,
1450 &values.shared_bytes)) {
1451 return false;
1454 values.is_private_and_shared_valid = true;
1455 return true;
1458 bool TaskManagerModel::CacheWebCoreStats(int index) const {
1459 PerResourceValues& values(GetPerResourceValues(index));
1460 if (!values.is_webcore_stats_valid) {
1461 if (!GetResource(index)->ReportsCacheStats())
1462 return false;
1463 values.is_webcore_stats_valid = true;
1464 values.webcore_stats = GetResource(index)->GetWebCoreCacheStats();
1466 return true;
1469 bool TaskManagerModel::CacheV8Memory(int index) const {
1470 PerResourceValues& values(GetPerResourceValues(index));
1471 if (!values.is_v8_memory_valid) {
1472 if (!GetResource(index)->ReportsV8MemoryStats())
1473 return false;
1474 values.is_v8_memory_valid = true;
1475 values.v8_memory_allocated = GetResource(index)->GetV8MemoryAllocated();
1476 values.v8_memory_used = GetResource(index)->GetV8MemoryUsed();
1478 return true;
1481 void TaskManagerModel::AddResourceProvider(ResourceProvider* provider) {
1482 DCHECK(provider);
1483 providers_.push_back(provider);
1486 TaskManagerModel::PerResourceValues& TaskManagerModel::GetPerResourceValues(
1487 int index) const {
1488 return per_resource_cache_[GetResource(index)];
1491 Resource* TaskManagerModel::GetResource(int index) const {
1492 CHECK_GE(index, 0);
1493 CHECK_LT(index, static_cast<int>(resources_.size()));
1494 return resources_[index];
1497 ////////////////////////////////////////////////////////////////////////////////
1498 // TaskManager class
1499 ////////////////////////////////////////////////////////////////////////////////
1500 // static
1501 void TaskManager::RegisterPrefs(PrefRegistrySimple* registry) {
1502 registry->RegisterDictionaryPref(prefs::kTaskManagerWindowPlacement);
1505 bool TaskManager::IsBrowserProcess(int index) const {
1506 // If some of the selection is out of bounds, ignore. This may happen when
1507 // killing a process that manages several pages.
1508 return index < model_->ResourceCount() &&
1509 model_->GetProcess(index) == base::GetCurrentProcessHandle();
1512 void TaskManager::KillProcess(int index) {
1513 base::ProcessHandle process_handle = model_->GetProcess(index);
1514 DCHECK(process_handle);
1515 if (process_handle != base::GetCurrentProcessHandle()) {
1516 base::Process process =
1517 base::Process::DeprecatedGetProcessFromHandle(process_handle);
1518 process.Terminate(content::RESULT_CODE_KILLED, false);
1522 void TaskManager::ActivateProcess(int index) {
1523 // GetResourceWebContents returns a pointer to the relevant web contents for
1524 // the resource. If the index doesn't correspond to any web contents
1525 // (i.e. refers to the Browser process or a plugin), GetWebContents will
1526 // return NULL.
1527 WebContents* chosen_web_contents = model_->GetResourceWebContents(index);
1528 if (chosen_web_contents && chosen_web_contents->GetDelegate())
1529 chosen_web_contents->GetDelegate()->ActivateContents(chosen_web_contents);
1532 void TaskManager::AddResource(Resource* resource) {
1533 model_->AddResource(resource);
1536 void TaskManager::RemoveResource(Resource* resource) {
1537 model_->RemoveResource(resource);
1540 void TaskManager::OnWindowClosed() {
1541 model_->StopUpdating();
1544 void TaskManager::ModelChanged() {
1545 model_->ModelChanged();
1548 // static
1549 TaskManager* TaskManager::GetInstance() {
1550 return Singleton<TaskManager>::get();
1553 void TaskManager::OpenAboutMemory(chrome::HostDesktopType desktop_type) {
1554 Profile* profile = ProfileManager::GetLastUsedProfileAllowedByPolicy();
1555 if (profile->IsGuestSession() && !g_browser_process->local_state()->
1556 GetBoolean(prefs::kBrowserGuestModeEnabled)) {
1557 UserManager::Show(base::FilePath(),
1558 profiles::USER_MANAGER_NO_TUTORIAL,
1559 profiles::USER_MANAGER_SELECT_PROFILE_CHROME_MEMORY);
1560 return;
1563 chrome::NavigateParams params(
1564 profile, GURL(chrome::kChromeUIMemoryURL), ui::PAGE_TRANSITION_LINK);
1565 params.disposition = NEW_FOREGROUND_TAB;
1566 params.host_desktop_type = desktop_type;
1567 chrome::Navigate(&params);
1570 TaskManager::TaskManager()
1571 : model_(new TaskManagerModel(this)) {
1574 TaskManager::~TaskManager() {