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