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