Updating trunk VERSION from 1949.0 to 1950.0
[chromium.git] / chrome / browser / task_manager / task_manager.cc
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/task_manager/task_manager.h"
6
7 #include "base/bind.h"
8 #include "base/compiler_specific.h"
9 #include "base/i18n/number_formatting.h"
10 #include "base/i18n/rtl.h"
11 #include "base/process_util.h"
12 #include "base/rand_util.h"
13 #include "base/string_number_conversions.h"
14 #include "base/stringprintf.h"
15 #include "base/threading/thread.h"
16 #include "base/utf_string_conversions.h"
17 #include "chrome/browser/background/background_contents_service.h"
18 #include "chrome/browser/background/background_contents_service_factory.h"
19 #include "chrome/browser/browser_process.h"
20 #include "chrome/browser/extensions/extension_host.h"
21 #include "chrome/browser/extensions/extension_process_manager.h"
22 #include "chrome/browser/prefs/pref_service.h"
23 #include "chrome/browser/profiles/profile_manager.h"
24 #include "chrome/browser/task_manager/task_manager_resource_providers.h"
25 #include "chrome/browser/task_manager/task_manager_worker_resource_provider.h"
26 #include "chrome/browser/ui/browser_list.h"
27 #include "chrome/browser/ui/browser_window.h"
28 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
29 #include "chrome/common/chrome_view_type.h"
30 #include "chrome/common/pref_names.h"
31 #include "chrome/common/url_constants.h"
32 #include "content/public/browser/browser_child_process_host.h"
33 #include "content/public/browser/browser_thread.h"
34 #include "content/public/browser/render_view_host.h"
35 #include "content/public/browser/render_view_host_delegate.h"
36 #include "content/public/browser/resource_request_info.h"
37 #include "content/public/browser/web_contents.h"
38 #include "content/public/common/result_codes.h"
39 #include "grit/chromium_strings.h"
40 #include "grit/generated_resources.h"
41 #include "grit/ui_resources.h"
42 #include "third_party/skia/include/core/SkBitmap.h"
43 #include "ui/base/l10n/l10n_util.h"
44 #include "ui/base/resource/resource_bundle.h"
45 #include "ui/base/text/bytes_formatting.h"
46 #include "unicode/coll.h"
47
48 using content::BrowserThread;
49 using content::OpenURLParams;
50 using content::Referrer;
51 using content::ResourceRequestInfo;
52
53 namespace {
54
55 // The delay between updates of the information (in ms).
56 #if defined(OS_MACOSX)
57 // Match Activity Monitor's default refresh rate.
58 const int kUpdateTimeMs = 2000;
59 #else
60 const int kUpdateTimeMs = 1000;
61 #endif
62
63 template <class T>
64 int ValueCompare(T value1, T value2) {
65   if (value1 < value2)
66     return -1;
67   if (value1 == value2)
68     return 0;
69   return 1;
70 }
71
72 string16 FormatStatsSize(const WebKit::WebCache::ResourceTypeStat& stat) {
73   return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_CACHE_SIZE_CELL_TEXT,
74       ui::FormatBytesWithUnits(stat.size, ui::DATA_UNITS_KIBIBYTE, false),
75       ui::FormatBytesWithUnits(stat.liveSize, ui::DATA_UNITS_KIBIBYTE, false));
76 }
77
78 }  // namespace
79
80 ////////////////////////////////////////////////////////////////////////////////
81 // TaskManagerModel class
82 ////////////////////////////////////////////////////////////////////////////////
83
84 TaskManagerModel::TaskManagerModel(TaskManager* task_manager)
85     : update_requests_(0),
86       update_state_(IDLE),
87       goat_salt_(base::RandUint64()),
88       last_unique_id_(0) {
89   AddResourceProvider(
90       new TaskManagerBrowserProcessResourceProvider(task_manager));
91   AddResourceProvider(
92       new TaskManagerBackgroundContentsResourceProvider(task_manager));
93   AddResourceProvider(new TaskManagerTabContentsResourceProvider(task_manager));
94   AddResourceProvider(
95       new TaskManagerChildProcessResourceProvider(task_manager));
96   AddResourceProvider(
97       new TaskManagerExtensionProcessResourceProvider(task_manager));
98
99 #if defined(ENABLE_NOTIFICATIONS)
100   TaskManager::ResourceProvider* provider =
101       TaskManagerNotificationResourceProvider::Create(task_manager);
102   if (provider)
103     AddResourceProvider(provider);
104 #endif
105
106   AddResourceProvider(new TaskManagerWorkerResourceProvider(task_manager));
107 }
108
109 TaskManagerModel::~TaskManagerModel() {
110 }
111
112 int TaskManagerModel::ResourceCount() const {
113   return resources_.size();
114 }
115
116 int TaskManagerModel::GroupCount() const {
117   return group_map_.size();
118 }
119
120 void TaskManagerModel::AddObserver(TaskManagerModelObserver* observer) {
121   observer_list_.AddObserver(observer);
122 }
123
124 void TaskManagerModel::RemoveObserver(TaskManagerModelObserver* observer) {
125   observer_list_.RemoveObserver(observer);
126 }
127
128 int TaskManagerModel::GetResourceUniqueId(int index) const {
129   CHECK_LT(index, ResourceCount());
130   return resources_[index]->get_unique_id();
131 }
132
133 int TaskManagerModel::GetResourceIndexByUniqueId(const int unique_id) const {
134   for (int resource_index = 0; resource_index < ResourceCount();
135        ++resource_index) {
136     if (GetResourceUniqueId(resource_index) == unique_id)
137       return resource_index;
138   }
139   return -1;
140 }
141
142 string16 TaskManagerModel::GetResourceTitle(int index) const {
143   CHECK_LT(index, ResourceCount());
144   return resources_[index]->GetTitle();
145 }
146
147 string16 TaskManagerModel::GetResourceProfileName(int index) const {
148   CHECK_LT(index, ResourceCount());
149   return resources_[index]->GetProfileName();
150 }
151
152 int64 TaskManagerModel::GetNetworkUsage(int index) const {
153   CHECK_LT(index, ResourceCount());
154   return GetNetworkUsage(resources_[index]);
155 }
156
157 string16 TaskManagerModel::GetResourceNetworkUsage(int index) const {
158   int64 net_usage = GetNetworkUsage(index);
159   if (net_usage == -1)
160     return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT);
161   if (net_usage == 0)
162     return ASCIIToUTF16("0");
163   string16 net_byte = ui::FormatSpeed(net_usage);
164   // Force number string to have LTR directionality.
165   return base::i18n::GetDisplayStringInLTRDirectionality(net_byte);
166 }
167
168 double TaskManagerModel::GetCPUUsage(int index) const {
169   CHECK_LT(index, ResourceCount());
170   return GetCPUUsage(resources_[index]);
171 }
172
173 string16 TaskManagerModel::GetResourceCPUUsage(int index) const {
174   CHECK_LT(index, ResourceCount());
175   return UTF8ToUTF16(base::StringPrintf(
176 #if defined(OS_MACOSX)
177       // Activity Monitor shows %cpu with one decimal digit -- be
178       // consistent with that.
179       "%.1f",
180 #else
181       "%.0f",
182 #endif
183       GetCPUUsage(resources_[index])));
184 }
185
186 string16 TaskManagerModel::GetResourcePrivateMemory(int index) const {
187   size_t private_mem;
188   if (!GetPrivateMemory(index, &private_mem))
189     return ASCIIToUTF16("N/A");
190   return GetMemCellText(private_mem);
191 }
192
193 string16 TaskManagerModel::GetResourceSharedMemory(int index) const {
194   size_t shared_mem;
195   if (!GetSharedMemory(index, &shared_mem))
196     return ASCIIToUTF16("N/A");
197   return GetMemCellText(shared_mem);
198 }
199
200 string16 TaskManagerModel::GetResourcePhysicalMemory(int index) const {
201   size_t phys_mem;
202   GetPhysicalMemory(index, &phys_mem);
203   return GetMemCellText(phys_mem);
204 }
205
206 int TaskManagerModel::GetProcessId(int index) const {
207   CHECK_LT(index, ResourceCount());
208   return base::GetProcId(resources_[index]->GetProcess());
209 }
210
211 string16 TaskManagerModel::GetResourceProcessId(int index) const {
212   return base::IntToString16(GetProcessId(index));
213 }
214
215 string16 TaskManagerModel::GetResourceGoatsTeleported(int index) const {
216   CHECK_LT(index, ResourceCount());
217   return base::FormatNumber(GetGoatsTeleported(index));
218 }
219
220 string16 TaskManagerModel::GetResourceWebCoreImageCacheSize(
221     int index) const {
222   CHECK_LT(index, ResourceCount());
223   if (!resources_[index]->ReportsCacheStats())
224     return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT);
225   const WebKit::WebCache::ResourceTypeStats stats(
226       resources_[index]->GetWebCoreCacheStats());
227   return FormatStatsSize(stats.images);
228 }
229
230 string16 TaskManagerModel::GetResourceWebCoreScriptsCacheSize(
231     int index) const {
232   CHECK_LT(index, ResourceCount());
233   if (!resources_[index]->ReportsCacheStats())
234     return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT);
235   const WebKit::WebCache::ResourceTypeStats stats(
236       resources_[index]->GetWebCoreCacheStats());
237   return FormatStatsSize(stats.scripts);
238 }
239
240 string16 TaskManagerModel::GetResourceWebCoreCSSCacheSize(
241     int index) const {
242   CHECK_LT(index, ResourceCount());
243   if (!resources_[index]->ReportsCacheStats())
244     return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT);
245   const WebKit::WebCache::ResourceTypeStats stats(
246       resources_[index]->GetWebCoreCacheStats());
247   return FormatStatsSize(stats.cssStyleSheets);
248 }
249
250 string16 TaskManagerModel::GetResourceFPS(
251     int index) const {
252   CHECK_LT(index, ResourceCount());
253   if (!resources_[index]->ReportsFPS())
254     return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT);
255   double fps = resources_[index]->GetFPS();
256   return UTF8ToUTF16(base::StringPrintf("%.0f", fps));
257 }
258
259 string16 TaskManagerModel::GetResourceSqliteMemoryUsed(int index) const {
260   CHECK_LT(index, ResourceCount());
261   if (!resources_[index]->ReportsSqliteMemoryUsed())
262     return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT);
263   return GetMemCellText(resources_[index]->SqliteMemoryUsedBytes());
264 }
265
266 string16 TaskManagerModel::GetResourceV8MemoryAllocatedSize(
267     int index) const {
268   if (!resources_[index]->ReportsV8MemoryStats())
269     return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT);
270   return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_CACHE_SIZE_CELL_TEXT,
271       ui::FormatBytesWithUnits(resources_[index]->GetV8MemoryAllocated(),
272                                ui::DATA_UNITS_KIBIBYTE,
273                                false),
274       ui::FormatBytesWithUnits(resources_[index]->GetV8MemoryUsed(),
275                                ui::DATA_UNITS_KIBIBYTE,
276                                false));
277 }
278
279 bool TaskManagerModel::IsResourceFirstInGroup(int index) const {
280   CHECK_LT(index, ResourceCount());
281   TaskManager::Resource* resource = resources_[index];
282   GroupMap::const_iterator iter = group_map_.find(resource->GetProcess());
283   DCHECK(iter != group_map_.end());
284   const ResourceList* group = iter->second;
285   return ((*group)[0] == resource);
286 }
287
288 bool TaskManagerModel::IsResourceLastInGroup(int index) const {
289   CHECK_LT(index, ResourceCount());
290   TaskManager::Resource* resource = resources_[index];
291   GroupMap::const_iterator iter = group_map_.find(resource->GetProcess());
292   DCHECK(iter != group_map_.end());
293   const ResourceList* group = iter->second;
294   return (group->back() == resource);
295 }
296
297 bool TaskManagerModel::IsBackgroundResource(int index) const {
298   CHECK_LT(index, ResourceCount());
299   return resources_[index]->IsBackground();
300 }
301
302 SkBitmap TaskManagerModel::GetResourceIcon(int index) const {
303   CHECK_LT(index, ResourceCount());
304   SkBitmap icon = resources_[index]->GetIcon();
305   if (!icon.isNull())
306     return icon;
307
308   static SkBitmap* default_icon = ResourceBundle::GetSharedInstance().
309       GetBitmapNamed(IDR_DEFAULT_FAVICON);
310   return *default_icon;
311 }
312
313 TaskManagerModel::GroupRange
314 TaskManagerModel::GetGroupRangeForResource(int index) const {
315   CHECK_LT(index, ResourceCount());
316   TaskManager::Resource* resource = resources_[index];
317   GroupMap::const_iterator group_iter =
318       group_map_.find(resource->GetProcess());
319   DCHECK(group_iter != group_map_.end());
320   ResourceList* group = group_iter->second;
321   DCHECK(group);
322   if (group->size() == 1) {
323     return std::make_pair(index, 1);
324   } else {
325     for (int i = index; i >= 0; --i) {
326       if (resources_[i] == (*group)[0])
327         return std::make_pair(i, group->size());
328     }
329     NOTREACHED();
330     return std::make_pair(-1, -1);
331   }
332 }
333
334 int TaskManagerModel::GetGroupIndexForResource(int index) const {
335   int group_index = -1;
336   for (int i = 0; i <= index; ++i) {
337     if (IsResourceFirstInGroup(i))
338         group_index++;
339   }
340
341   DCHECK_NE(group_index, -1);
342   return group_index;
343 }
344
345 int TaskManagerModel::GetResourceIndexForGroup(int group_index,
346                                                int index_in_group) const {
347   int group_count = -1;
348   int count_in_group = -1;
349   for (int i = 0; i < ResourceCount(); ++i) {
350     if (IsResourceFirstInGroup(i))
351       group_count++;
352
353     if (group_count == group_index) {
354       count_in_group++;
355       if (count_in_group == index_in_group)
356         return i;
357     } else if (group_count > group_index) {
358       break;
359     }
360   }
361
362   NOTREACHED();
363   return -1;
364 }
365
366 int TaskManagerModel::CompareValues(int row1, int row2, int col_id) const {
367   CHECK(row1 < ResourceCount() && row2 < ResourceCount());
368   if (col_id == IDS_TASK_MANAGER_PAGE_COLUMN) {
369     // Let's do the default, string compare on the resource title.
370     static icu::Collator* collator = NULL;
371     if (!collator) {
372       UErrorCode create_status = U_ZERO_ERROR;
373       collator = icu::Collator::createInstance(create_status);
374       if (!U_SUCCESS(create_status)) {
375         collator = NULL;
376         NOTREACHED();
377       }
378     }
379     string16 title1 = GetResourceTitle(row1);
380     string16 title2 = GetResourceTitle(row2);
381     UErrorCode compare_status = U_ZERO_ERROR;
382     UCollationResult compare_result = collator->compare(
383         static_cast<const UChar*>(title1.c_str()),
384         static_cast<int>(title1.length()),
385         static_cast<const UChar*>(title2.c_str()),
386         static_cast<int>(title2.length()),
387         compare_status);
388     DCHECK(U_SUCCESS(compare_status));
389     return compare_result;
390   } else if (col_id == IDS_TASK_MANAGER_PROFILE_NAME_COLUMN) {
391     string16 profile1 = GetResourceProfileName(row1);
392     string16 profile2 = GetResourceProfileName(row2);
393     return profile1.compare(0, profile1.length(), profile2, 0,
394                             profile2.length());
395   } else if (col_id == IDS_TASK_MANAGER_NET_COLUMN) {
396     return ValueCompare<int64>(GetNetworkUsage(resources_[row1]),
397                                GetNetworkUsage(resources_[row2]));
398   } else if (col_id == IDS_TASK_MANAGER_CPU_COLUMN) {
399     return ValueCompare<double>(GetCPUUsage(resources_[row1]),
400                                 GetCPUUsage(resources_[row2]));
401   } else if (col_id == IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN) {
402     size_t value1;
403     size_t value2;
404     if (!GetPrivateMemory(row1, &value1) || !GetPrivateMemory(row2, &value2))
405       return 0;
406     return ValueCompare<size_t>(value1, value2);
407   } else if (col_id == IDS_TASK_MANAGER_SHARED_MEM_COLUMN) {
408     size_t value1;
409     size_t value2;
410     if (!GetSharedMemory(row1, &value1) || !GetSharedMemory(row2, &value2))
411       return 0;
412     return ValueCompare<size_t>(value1, value2);
413   } else if (col_id == IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN) {
414     size_t value1;
415     size_t value2;
416     if (!GetPhysicalMemory(row1, &value1) ||
417         !GetPhysicalMemory(row2, &value2))
418       return 0;
419     return ValueCompare<size_t>(value1, value2);
420   } else if (col_id == IDS_TASK_MANAGER_PROCESS_ID_COLUMN) {
421     int proc1_id = base::GetProcId(resources_[row1]->GetProcess());
422     int proc2_id = base::GetProcId(resources_[row2]->GetProcess());
423     return ValueCompare<int>(proc1_id, proc2_id);
424   } else if (col_id == IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN ||
425              col_id == IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN ||
426              col_id == IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN) {
427     WebKit::WebCache::ResourceTypeStats stats1 = { { 0 } };
428     WebKit::WebCache::ResourceTypeStats stats2 = { { 0 } };
429     if (resources_[row1]->ReportsCacheStats())
430       stats1 = resources_[row1]->GetWebCoreCacheStats();
431     if (resources_[row2]->ReportsCacheStats())
432       stats2 = resources_[row2]->GetWebCoreCacheStats();
433     if (IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN == col_id)
434       return ValueCompare<size_t>(stats1.images.size, stats2.images.size);
435     if (IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN == col_id)
436       return ValueCompare<size_t>(stats1.scripts.size, stats2.scripts.size);
437     DCHECK_EQ(IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN, col_id);
438     return ValueCompare<size_t>(stats1.cssStyleSheets.size,
439                                 stats2.cssStyleSheets.size);
440   } else if (col_id == IDS_TASK_MANAGER_FPS_COLUMN) {
441     return ValueCompare<float>(resources_[row1]->GetFPS(),
442                                resources_[row2]->GetFPS());
443   } else if (col_id == IDS_TASK_MANAGER_GOATS_TELEPORTED_COLUMN) {
444     return ValueCompare<int>(GetGoatsTeleported(row1),
445                              GetGoatsTeleported(row2));
446   } else if (col_id == IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN) {
447     size_t value1;
448     size_t value2;
449     bool reports_v8_memory1 = GetV8Memory(row1, &value1);
450     bool reports_v8_memory2 = GetV8Memory(row2, &value2);
451     if (reports_v8_memory1 == reports_v8_memory2)
452       return ValueCompare<size_t>(value1, value2);
453     else
454       return reports_v8_memory1 ? 1 : -1;
455   } else {
456     NOTREACHED();
457     return 0;
458   }
459 }
460
461 base::ProcessHandle TaskManagerModel::GetResourceProcessHandle(int index)
462     const {
463   CHECK_LT(index, ResourceCount());
464   return resources_[index]->GetProcess();
465 }
466
467 TaskManager::Resource::Type TaskManagerModel::GetResourceType(int index) const {
468   CHECK_LT(index, ResourceCount());
469   return resources_[index]->GetType();
470 }
471
472 TabContentsWrapper* TaskManagerModel::GetResourceTabContents(int index) const {
473   CHECK_LT(index, ResourceCount());
474   return resources_[index]->GetTabContents();
475 }
476
477 const Extension* TaskManagerModel::GetResourceExtension(int index) const {
478   CHECK_LT(index, ResourceCount());
479   return resources_[index]->GetExtension();
480 }
481
482 int64 TaskManagerModel::GetNetworkUsage(TaskManager::Resource* resource)
483     const {
484   int64 net_usage = GetNetworkUsageForResource(resource);
485   if (net_usage == 0 && !resource->SupportNetworkUsage())
486     return -1;
487   return net_usage;
488 }
489
490 double TaskManagerModel::GetCPUUsage(TaskManager::Resource* resource) const {
491   CPUUsageMap::const_iterator iter =
492       cpu_usage_map_.find(resource->GetProcess());
493   if (iter == cpu_usage_map_.end())
494     return 0;
495   return iter->second;
496 }
497
498 bool TaskManagerModel::GetPrivateMemory(int index, size_t* result) const {
499   base::ProcessHandle handle = resources_[index]->GetProcess();
500   MemoryUsageMap::const_iterator iter = memory_usage_map_.find(handle);
501   if (iter == memory_usage_map_.end()) {
502     MemoryUsageEntry usage;
503     if (!GetAndCacheMemoryMetrics(handle, &usage))
504       return false;
505
506     *result = usage.first;
507   } else {
508     *result = iter->second.first;
509   }
510
511   return true;
512 }
513
514 bool TaskManagerModel::GetSharedMemory(int index, size_t* result) const {
515   base::ProcessHandle handle = resources_[index]->GetProcess();
516   MemoryUsageMap::const_iterator iter = memory_usage_map_.find(handle);
517   if (iter == memory_usage_map_.end()) {
518     MemoryUsageEntry usage;
519     if (!GetAndCacheMemoryMetrics(handle, &usage))
520       return false;
521
522     *result = usage.second;
523   } else {
524     *result = iter->second.second;
525   }
526
527   return true;
528 }
529
530 bool TaskManagerModel::GetPhysicalMemory(int index, size_t* result) const {
531   *result = 0;
532   base::ProcessMetrics* process_metrics;
533   if (!GetProcessMetricsForRow(index, &process_metrics))
534     return false;
535   base::WorkingSetKBytes ws_usage;
536   if (!process_metrics->GetWorkingSetKBytes(&ws_usage))
537     return false;
538
539   // Memory = working_set.private + working_set.shareable.
540   // We exclude the shared memory.
541   size_t total_bytes = process_metrics->GetWorkingSetSize();
542   total_bytes -= ws_usage.shared * 1024;
543   *result = total_bytes;
544   return true;
545 }
546
547 bool TaskManagerModel::GetWebCoreCacheStats(
548     int index, WebKit::WebCache::ResourceTypeStats* result) const {
549   if (!resources_[index]->ReportsCacheStats())
550     return false;
551
552   *result = resources_[index]->GetWebCoreCacheStats();
553   return true;
554 }
555
556 bool TaskManagerModel::GetFPS(int index, float* result) const {
557   *result = 0;
558   if (!resources_[index]->ReportsFPS())
559     return false;
560
561   *result = resources_[index]->GetFPS();
562   return true;
563 }
564
565 bool TaskManagerModel::GetSqliteMemoryUsedBytes(
566     int index, size_t* result) const {
567   *result = 0;
568   if (!resources_[index]->ReportsSqliteMemoryUsed())
569     return false;
570
571   *result = resources_[index]->SqliteMemoryUsedBytes();
572   return true;
573 }
574
575 bool TaskManagerModel::GetV8Memory(int index, size_t* result) const {
576   *result = 0;
577   if (!resources_[index]->ReportsV8MemoryStats())
578     return false;
579
580   *result = resources_[index]->GetV8MemoryAllocated();
581   return true;
582 }
583
584 bool TaskManagerModel::CanActivate(int index) const {
585   CHECK_LT(index, ResourceCount());
586   return GetResourceTabContents(index) != NULL;
587 }
588
589 bool TaskManagerModel::CanInspect(int index) const {
590   CHECK_LT(index, ResourceCount());
591   return resources_[index]->CanInspect();
592 }
593
594 void TaskManagerModel::Inspect(int index) const {
595   CHECK_LT(index, ResourceCount());
596   resources_[index]->Inspect();
597 }
598
599 int TaskManagerModel::GetGoatsTeleported(int index) const {
600   int seed = goat_salt_ * (index + 1);
601   return (seed >> 16) & 255;
602 }
603
604 string16 TaskManagerModel::GetMemCellText(int64 number) const {
605 #if !defined(OS_MACOSX)
606   string16 str = base::FormatNumber(number / 1024);
607
608   // Adjust number string if necessary.
609   base::i18n::AdjustStringForLocaleDirection(&str);
610   return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_MEM_CELL_TEXT, str);
611 #else
612   // System expectation is to show "100 kB", "200 MB", etc.
613   // TODO(thakis): Switch to metric units (as opposed to powers of two).
614   return ui::FormatBytes(number);
615 #endif
616 }
617
618 void TaskManagerModel::StartUpdating() {
619   // Multiple StartUpdating requests may come in, and we only need to take
620   // action the first time.
621   update_requests_++;
622   if (update_requests_ > 1)
623     return;
624   DCHECK_EQ(1, update_requests_);
625   DCHECK_NE(TASK_PENDING, update_state_);
626
627   // If update_state_ is STOPPING, it means a task is still pending.  Setting
628   // it to TASK_PENDING ensures the tasks keep being posted (by Refresh()).
629   if (update_state_ == IDLE) {
630       MessageLoop::current()->PostTask(
631           FROM_HERE,
632           base::Bind(&TaskManagerModel::Refresh, this));
633   }
634   update_state_ = TASK_PENDING;
635
636   // Notify resource providers that we are updating.
637   for (ResourceProviderList::iterator iter = providers_.begin();
638        iter != providers_.end(); ++iter) {
639     (*iter)->StartUpdating();
640   }
641
642   if (!resources_.empty()) {
643     FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_,
644                       OnReadyPeriodicalUpdate());
645   }
646 }
647
648 void TaskManagerModel::StopUpdating() {
649   // Don't actually stop updating until we have heard as many calls as those
650   // to StartUpdating.
651   update_requests_--;
652   if (update_requests_ > 0)
653     return;
654   // Make sure that update_requests_ cannot go negative.
655   CHECK_EQ(0, update_requests_);
656   DCHECK_EQ(TASK_PENDING, update_state_);
657   update_state_ = STOPPING;
658
659   // Notify resource providers that we are done updating.
660   for (ResourceProviderList::const_iterator iter = providers_.begin();
661        iter != providers_.end(); ++iter) {
662     (*iter)->StopUpdating();
663   }
664
665   // Must clear the resources before the next attempt to start updating.
666   Clear();
667 }
668
669 void TaskManagerModel::AddResourceProvider(
670     TaskManager::ResourceProvider* provider) {
671   DCHECK(provider);
672   providers_.push_back(provider);
673 }
674
675 void TaskManagerModel::AddResource(TaskManager::Resource* resource) {
676   resource->unique_id_ = ++last_unique_id_;
677
678   base::ProcessHandle process = resource->GetProcess();
679
680   ResourceList* group_entries = NULL;
681   GroupMap::const_iterator group_iter = group_map_.find(process);
682   int new_entry_index = 0;
683   if (group_iter == group_map_.end()) {
684     group_entries = new ResourceList();
685     group_map_[process] = group_entries;
686     group_entries->push_back(resource);
687
688     // Not part of a group, just put at the end of the list.
689     resources_.push_back(resource);
690     new_entry_index = static_cast<int>(resources_.size() - 1);
691   } else {
692     group_entries = group_iter->second;
693     group_entries->push_back(resource);
694
695     // Insert the new entry right after the last entry of its group.
696     ResourceList::iterator iter =
697         std::find(resources_.begin(),
698                   resources_.end(),
699                   (*group_entries)[group_entries->size() - 2]);
700     DCHECK(iter != resources_.end());
701     new_entry_index = static_cast<int>(iter - resources_.begin()) + 1;
702     resources_.insert(++iter, resource);
703   }
704
705   // Create the ProcessMetrics for this process if needed (not in map).
706   if (metrics_map_.find(process) == metrics_map_.end()) {
707     base::ProcessMetrics* pm =
708 #if !defined(OS_MACOSX)
709         base::ProcessMetrics::CreateProcessMetrics(process);
710 #else
711         base::ProcessMetrics::CreateProcessMetrics(
712             process, content::BrowserChildProcessHost::GetPortProvider());
713 #endif
714
715     metrics_map_[process] = pm;
716   }
717
718   // Notify the table that the contents have changed for it to redraw.
719   FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_,
720                     OnItemsAdded(new_entry_index, 1));
721 }
722
723 void TaskManagerModel::RemoveResource(TaskManager::Resource* resource) {
724   base::ProcessHandle process = resource->GetProcess();
725
726   // Find the associated group.
727   GroupMap::iterator group_iter = group_map_.find(process);
728   DCHECK(group_iter != group_map_.end());
729   ResourceList* group_entries = group_iter->second;
730
731   // Remove the entry from the group map.
732   ResourceList::iterator iter = std::find(group_entries->begin(),
733                                           group_entries->end(),
734                                           resource);
735   DCHECK(iter != group_entries->end());
736   group_entries->erase(iter);
737
738   // If there are no more entries for that process, do the clean-up.
739   if (group_entries->empty()) {
740     delete group_entries;
741     group_map_.erase(process);
742
743     // Nobody is using this process, we don't need the process metrics anymore.
744     MetricsMap::iterator pm_iter = metrics_map_.find(process);
745     DCHECK(pm_iter != metrics_map_.end());
746     if (pm_iter != metrics_map_.end()) {
747       delete pm_iter->second;
748       metrics_map_.erase(process);
749     }
750     // And we don't need the CPU usage anymore either.
751     CPUUsageMap::iterator cpu_iter = cpu_usage_map_.find(process);
752     if (cpu_iter != cpu_usage_map_.end())
753       cpu_usage_map_.erase(cpu_iter);
754   }
755
756   // Remove the entry from the model list.
757   iter = std::find(resources_.begin(), resources_.end(), resource);
758   DCHECK(iter != resources_.end());
759   int index = static_cast<int>(iter - resources_.begin());
760   resources_.erase(iter);
761
762   // Remove the entry from the network maps.
763   ResourceValueMap::iterator net_iter =
764       current_byte_count_map_.find(resource);
765   if (net_iter != current_byte_count_map_.end())
766     current_byte_count_map_.erase(net_iter);
767   net_iter = displayed_network_usage_map_.find(resource);
768   if (net_iter != displayed_network_usage_map_.end())
769     displayed_network_usage_map_.erase(net_iter);
770
771   // Notify the table that the contents have changed.
772   FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_,
773                     OnItemsRemoved(index, 1));
774 }
775
776 void TaskManagerModel::Clear() {
777   int size = ResourceCount();
778   if (size > 0) {
779     resources_.clear();
780
781     // Clear the groups.
782     for (GroupMap::iterator iter = group_map_.begin();
783          iter != group_map_.end(); ++iter) {
784       delete iter->second;
785     }
786     group_map_.clear();
787
788     // Clear the process related info.
789     for (MetricsMap::iterator iter = metrics_map_.begin();
790          iter != metrics_map_.end(); ++iter) {
791       delete iter->second;
792     }
793     metrics_map_.clear();
794     cpu_usage_map_.clear();
795
796     // Clear the network maps.
797     current_byte_count_map_.clear();
798     displayed_network_usage_map_.clear();
799
800     FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_,
801                       OnItemsRemoved(0, size));
802   }
803   last_unique_id_ = 0;
804 }
805
806 void TaskManagerModel::ModelChanged() {
807   // Notify the table that the contents have changed for it to redraw.
808   FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_, OnModelChanged());
809 }
810
811 void TaskManagerModel::NotifyResourceTypeStats(
812     base::ProcessId renderer_id,
813     const WebKit::WebCache::ResourceTypeStats& stats) {
814   for (ResourceList::iterator it = resources_.begin();
815        it != resources_.end(); ++it) {
816     if (base::GetProcId((*it)->GetProcess()) == renderer_id) {
817       (*it)->NotifyResourceTypeStats(stats);
818     }
819   }
820 }
821
822 void TaskManagerModel::NotifyFPS(base::ProcessId renderer_id,
823                                  int routing_id,
824                                  float fps) {
825   for (ResourceList::iterator it = resources_.begin();
826        it != resources_.end(); ++it) {
827     if (base::GetProcId((*it)->GetProcess()) == renderer_id &&
828         (*it)->GetRoutingID() == routing_id) {
829       (*it)->NotifyFPS(fps);
830     }
831   }
832 }
833
834 void TaskManagerModel::NotifyV8HeapStats(base::ProcessId renderer_id,
835                                          size_t v8_memory_allocated,
836                                          size_t v8_memory_used) {
837   for (ResourceList::iterator it = resources_.begin();
838        it != resources_.end(); ++it) {
839     if (base::GetProcId((*it)->GetProcess()) == renderer_id) {
840       (*it)->NotifyV8HeapStats(v8_memory_allocated, v8_memory_used);
841     }
842   }
843 }
844
845 void TaskManagerModel::Refresh() {
846   DCHECK_NE(IDLE, update_state_);
847
848   if (update_state_ == STOPPING) {
849     // We have been asked to stop.
850     update_state_ = IDLE;
851     return;
852   }
853
854   goat_salt_ = base::RandUint64();
855
856   // Compute the CPU usage values.
857   // Note that we compute the CPU usage for all resources (instead of doing it
858   // lazily) as process_util::GetCPUUsage() returns the CPU usage since the last
859   // time it was called, and not calling it everytime would skew the value the
860   // next time it is retrieved (as it would be for more than 1 cycle).
861   cpu_usage_map_.clear();
862   for (ResourceList::iterator iter = resources_.begin();
863        iter != resources_.end(); ++iter) {
864     base::ProcessHandle process = (*iter)->GetProcess();
865     CPUUsageMap::iterator cpu_iter = cpu_usage_map_.find(process);
866     if (cpu_iter != cpu_usage_map_.end())
867       continue;  // Already computed.
868
869     MetricsMap::iterator metrics_iter = metrics_map_.find(process);
870     DCHECK(metrics_iter != metrics_map_.end());
871     cpu_usage_map_[process] = metrics_iter->second->GetCPUUsage();
872   }
873
874   // Clear the memory values so they can be querried lazily.
875   memory_usage_map_.clear();
876
877   // Compute the new network usage values.
878   displayed_network_usage_map_.clear();
879   base::TimeDelta update_time =
880       base::TimeDelta::FromMilliseconds(kUpdateTimeMs);
881   for (ResourceValueMap::iterator iter = current_byte_count_map_.begin();
882        iter != current_byte_count_map_.end(); ++iter) {
883     if (update_time > base::TimeDelta::FromSeconds(1)) {
884       int divider = update_time.InSeconds();
885       displayed_network_usage_map_[iter->first] = iter->second / divider;
886     } else {
887       displayed_network_usage_map_[iter->first] = iter->second *
888           (1 / update_time.InSeconds());
889     }
890
891     // Then we reset the current byte count.
892     iter->second = 0;
893   }
894
895   // Let resources update themselves if they need to.
896   for (ResourceList::iterator iter = resources_.begin();
897        iter != resources_.end(); ++iter) {
898      (*iter)->Refresh();
899   }
900
901   if (!resources_.empty()) {
902     FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_,
903                       OnItemsChanged(0, ResourceCount()));
904   }
905
906   // Schedule the next update.
907   MessageLoop::current()->PostDelayedTask(
908       FROM_HERE,
909       base::Bind(&TaskManagerModel::Refresh, this),
910       base::TimeDelta::FromMilliseconds(kUpdateTimeMs));
911 }
912
913 int64 TaskManagerModel::GetNetworkUsageForResource(
914     TaskManager::Resource* resource) const {
915   ResourceValueMap::const_iterator iter =
916       displayed_network_usage_map_.find(resource);
917   if (iter == displayed_network_usage_map_.end())
918     return 0;
919   return iter->second;
920 }
921
922 void TaskManagerModel::BytesRead(BytesReadParam param) {
923   if (update_state_ != TASK_PENDING) {
924     // A notification sneaked in while we were stopping the updating, just
925     // ignore it.
926     return;
927   }
928
929   if (param.byte_count == 0) {
930     // Nothing to do if no bytes were actually read.
931     return;
932   }
933
934   // TODO(jcampan): this should be improved once we have a better way of
935   // linking a network notification back to the object that initiated it.
936   TaskManager::Resource* resource = NULL;
937   for (ResourceProviderList::iterator iter = providers_.begin();
938        iter != providers_.end(); ++iter) {
939     resource = (*iter)->GetResource(param.origin_pid,
940                                     param.render_process_host_child_id,
941                                     param.routing_id);
942     if (resource)
943       break;
944   }
945
946   if (resource == NULL) {
947     // We can't match a resource to the notification.  That might mean the
948     // tab that started a download was closed, or the request may have had
949     // no originating resource associated with it in the first place.
950     // We attribute orphaned/unaccounted activity to the Browser process.
951     CHECK(param.origin_pid || (param.render_process_host_child_id != -1));
952     param.origin_pid = 0;
953     param.render_process_host_child_id = param.routing_id = -1;
954     BytesRead(param);
955     return;
956   }
957
958   // We do support network usage, mark the resource as such so it can report 0
959   // instead of N/A.
960   if (!resource->SupportNetworkUsage())
961     resource->SetSupportNetworkUsage();
962
963   ResourceValueMap::const_iterator iter_res =
964       current_byte_count_map_.find(resource);
965   if (iter_res == current_byte_count_map_.end())
966     current_byte_count_map_[resource] = param.byte_count;
967   else
968     current_byte_count_map_[resource] = iter_res->second + param.byte_count;
969 }
970
971
972 void TaskManagerModel::NotifyBytesRead(const net::URLRequest& request,
973                                        int byte_count) {
974   // Only net::URLRequestJob instances created by the ResourceDispatcherHost
975   // have an associated ResourceRequestInfo.
976   const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(&request);
977
978   // have a render view associated.  All other jobs will have -1 returned for
979   // the render process child and routing ids - the jobs may still match a
980   // resource based on their origin id, otherwise BytesRead() will attribute
981   // the activity to the Browser resource.
982   int render_process_host_child_id = -1, routing_id = -1;
983   if (info)
984     info->GetAssociatedRenderView(&render_process_host_child_id, &routing_id);
985
986   // Get the origin PID of the request's originator.  This will only be set for
987   // plugins - for renderer or browser initiated requests it will be zero.
988   int origin_pid = 0;
989   if (info)
990     origin_pid = info->GetOriginPID();
991
992   // This happens in the IO thread, post it to the UI thread.
993   BrowserThread::PostTask(
994       BrowserThread::UI, FROM_HERE,
995       base::Bind(&TaskManagerModel::BytesRead, this,
996                  BytesReadParam(origin_pid, render_process_host_child_id,
997                                 routing_id, byte_count)));
998 }
999
1000 bool TaskManagerModel::GetProcessMetricsForRow(
1001     int row, base::ProcessMetrics** proc_metrics) const {
1002   DCHECK(row < ResourceCount());
1003   *proc_metrics = NULL;
1004
1005   MetricsMap::const_iterator iter =
1006       metrics_map_.find(resources_[row]->GetProcess());
1007   if (iter == metrics_map_.end())
1008     return false;
1009   *proc_metrics = iter->second;
1010   return true;
1011 }
1012
1013 ////////////////////////////////////////////////////////////////////////////////
1014 // TaskManager class
1015 ////////////////////////////////////////////////////////////////////////////////
1016
1017 // static
1018 void TaskManager::RegisterPrefs(PrefService* prefs) {
1019   prefs->RegisterDictionaryPref(prefs::kTaskManagerWindowPlacement);
1020 }
1021
1022 TaskManager::TaskManager()
1023     : ALLOW_THIS_IN_INITIALIZER_LIST(model_(new TaskManagerModel(this))) {
1024 }
1025
1026 TaskManager::~TaskManager() {
1027 }
1028
1029 bool TaskManager::IsBrowserProcess(int index) const {
1030   // If some of the selection is out of bounds, ignore. This may happen when
1031   // killing a process that manages several pages.
1032   return index < model_->ResourceCount() &&
1033       model_->GetResourceProcessHandle(index) ==
1034       base::GetCurrentProcessHandle();
1035 }
1036
1037 void TaskManager::KillProcess(int index) {
1038   base::ProcessHandle process = model_->GetResourceProcessHandle(index);
1039   DCHECK(process);
1040   if (process != base::GetCurrentProcessHandle())
1041     base::KillProcess(process, content::RESULT_CODE_KILLED, false);
1042 }
1043
1044 void TaskManager::ActivateProcess(int index) {
1045   // GetResourceTabContents returns a pointer to the relevant tab contents for
1046   // the resource.  If the index doesn't correspond to a Tab (i.e. refers to
1047   // the Browser process or a plugin), GetTabContents will return NULL.
1048   TabContentsWrapper* chosen_tab_contents =
1049       model_->GetResourceTabContents(index);
1050   if (chosen_tab_contents) {
1051     chosen_tab_contents->web_contents()->GetRenderViewHost()->GetDelegate()->
1052         Activate();
1053   }
1054 }
1055
1056 void TaskManager::AddResource(Resource* resource) {
1057   model_->AddResource(resource);
1058 }
1059
1060 void TaskManager::RemoveResource(Resource* resource) {
1061   model_->RemoveResource(resource);
1062 }
1063
1064 void TaskManager::OnWindowClosed() {
1065   model_->StopUpdating();
1066 }
1067
1068 void TaskManager::ModelChanged() {
1069   model_->ModelChanged();
1070 }
1071
1072 // static
1073 TaskManager* TaskManager::GetInstance() {
1074   return Singleton<TaskManager>::get();
1075 }
1076
1077 void TaskManager::OpenAboutMemory() {
1078   Browser* browser = BrowserList::GetLastActive();
1079   OpenURLParams params(
1080       GURL(chrome::kChromeUIMemoryURL), Referrer(), NEW_FOREGROUND_TAB,
1081       content::PAGE_TRANSITION_LINK, false);
1082
1083   if (!browser) {
1084     // On OS X, the task manager can be open without any open browser windows.
1085     if (!g_browser_process || !g_browser_process->profile_manager())
1086       return;
1087     Profile* profile =
1088         g_browser_process->profile_manager()->GetLastUsedProfile();
1089     if (!profile)
1090       return;
1091     browser = Browser::Create(profile);
1092     browser->OpenURL(params);
1093   } else {
1094     browser->OpenURL(params);
1095
1096     // In case the browser window is minimized, show it. If |browser| is a
1097     // non-tabbed window, the call to OpenURL above will have opened a
1098     // TabContents in a tabbed browser, so we need to grab it with
1099     // GetLastActive before the call to show().
1100     if (!browser->is_type_tabbed()) {
1101       browser = BrowserList::GetLastActive();
1102       DCHECK(browser);
1103     }
1104   }
1105   browser->window()->Show();
1106 }
1107
1108 bool TaskManagerModel::GetAndCacheMemoryMetrics(base::ProcessHandle handle,
1109                                                 MemoryUsageEntry* usage) const {
1110   MetricsMap::const_iterator iter = metrics_map_.find(handle);
1111   if (iter == metrics_map_.end())
1112     return false;
1113
1114   if (!iter->second->GetMemoryBytes(&usage->first, &usage->second))
1115     return false;
1116
1117   memory_usage_map_.insert(std::make_pair(handle, *usage));
1118   return true;
1119 }
1120
1121 namespace {
1122
1123 // Counts the number of extension background pages associated with this profile.
1124 int CountExtensionBackgroundPagesForProfile(Profile* profile) {
1125   int count = 0;
1126   ExtensionProcessManager* manager = profile->GetExtensionProcessManager();
1127   if (!manager)
1128     return count;
1129   for (ExtensionProcessManager::const_iterator iter = manager->begin();
1130        iter != manager->end();
1131        ++iter) {
1132     if ((*iter)->extension_host_type() ==
1133         chrome::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) {
1134       count++;
1135     }
1136   }
1137   return count;
1138 }
1139
1140 }  // namespace
1141
1142 // static
1143 int TaskManager::GetBackgroundPageCount() {
1144   int count = 0;
1145   ProfileManager* profile_manager = g_browser_process->profile_manager();
1146   if (!profile_manager)  // Null when running unit tests.
1147     return count;
1148   std::vector<Profile*> profiles(profile_manager->GetLoadedProfiles());
1149   for (std::vector<Profile*>::const_iterator iter = profiles.begin();
1150        iter != profiles.end();
1151        ++iter) {
1152     Profile* profile = *iter;
1153     // Count the number of Background Contents (background pages for hosted
1154     // apps). Incognito windows do not support hosted apps, so just check the
1155     // main profile.
1156     BackgroundContentsService* background_contents_service =
1157         BackgroundContentsServiceFactory::GetForProfile(profile);
1158     if (background_contents_service)
1159       count += background_contents_service->GetBackgroundContents().size();
1160
1161     // Count the number of extensions with background pages (including
1162     // incognito).
1163     count += CountExtensionBackgroundPagesForProfile(profile);
1164     if (profile->HasOffTheRecordProfile()) {
1165       count += CountExtensionBackgroundPagesForProfile(
1166           profile->GetOffTheRecordProfile());
1167     }
1168   }
1169   return count;
1170 }