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