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