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