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