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