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