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