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