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