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/ui/webui/task_manager/task_manager_handler.h"
      6 
      7 #include <algorithm>
      8 #include <functional>
      9 
     10 #include "base/bind.h"
     11 #include "base/bind_helpers.h"
     12 #include "base/strings/string_number_conversions.h"
     13 #include "base/values.h"
     14 #include "chrome/browser/profiles/profile.h"
     15 #include "chrome/browser/task_manager/task_manager.h"
     16 #include "chrome/browser/ui/host_desktop.h"
     17 #include "content/public/browser/render_view_host.h"
     18 #include "content/public/browser/web_contents.h"
     19 #include "content/public/browser/web_ui.h"
     20 #include "ui/gfx/image/image_skia.h"
     21 #include "ui/webui/web_ui_util.h"
     22 #include "webkit/common/webpreferences.h"
     23 
     24 namespace {
     25 
     26 struct ColumnType {
     27   const char* column_id;
     28   // Whether the column has the real value separately or not, instead of the
     29   // formatted value to display.
     30   const bool has_real_value;
     31   // Whether the column has single datum or multiple data in each group.
     32   const bool has_multiple_data;
     33 };
     34 
     35 const ColumnType kColumnsList[] = {
     36   {"type", false, false},
     37   {"processId", true, false},
     38   {"cpuUsage", true, false},
     39   {"physicalMemory", true, false},
     40   {"sharedMemory", true, false},
     41   {"privateMemory", true, false},
     42   {"webCoreImageCacheSize", true, false},
     43   {"webCoreImageCacheSize", true, false},
     44   {"webCoreScriptsCacheSize", true, false},
     45   {"webCoreCSSCacheSize", true, false},
     46   {"sqliteMemoryUsed", true, false},
     47   {"v8MemoryAllocatedSize", true, false},
     48   {"icon", false, true},
     49   {"title", false, true},
     50   {"profileName", false, true},
     51   {"networkUsage", true, true},
     52   {"fps", true, true},
     53   {"videoMemory", true, false},
     54   {"goatsTeleported", true, true},
     55   {"canInspect", false, true},
     56   {"canActivate", false, true}
     57 };
     58 
     59 }  // namespace
     60 
     61 TaskManagerHandler::TaskManagerHandler(TaskManager* tm)
     62     : task_manager_(tm),
     63       model_(tm->model()),
     64       is_enabled_(false) {
     65 }
     66 
     67 TaskManagerHandler::~TaskManagerHandler() {
     68   DisableTaskManager(NULL);
     69 }
     70 
     71 // TaskManagerHandler, public: -----------------------------------------------
     72 
     73 void TaskManagerHandler::OnModelChanged() {
     74   OnGroupChanged(0, model_->GroupCount());
     75 }
     76 
     77 void TaskManagerHandler::OnItemsChanged(const int start, const int length) {
     78   OnGroupChanged(0, model_->GroupCount());
     79 }
     80 
     81 void TaskManagerHandler::OnItemsAdded(const int start, const int length) {
     82 }
     83 
     84 void TaskManagerHandler::OnItemsRemoved(const int start, const int length) {
     85 }
     86 
     87 void TaskManagerHandler::RegisterMessages() {
     88   web_ui()->RegisterMessageCallback("killProcesses",
     89       base::Bind(&TaskManagerHandler::HandleKillProcesses,
     90                  base::Unretained(this)));
     91   web_ui()->RegisterMessageCallback("inspect",
     92       base::Bind(&TaskManagerHandler::HandleInspect,
     93                  base::Unretained(this)));
     94   web_ui()->RegisterMessageCallback("activatePage",
     95       base::Bind(&TaskManagerHandler::HandleActivatePage,
     96                  base::Unretained(this)));
     97   web_ui()->RegisterMessageCallback("openAboutMemory",
     98       base::Bind(&TaskManagerHandler::OpenAboutMemory,
     99                  base::Unretained(this)));
    100   web_ui()->RegisterMessageCallback("enableTaskManager",
    101       base::Bind(&TaskManagerHandler::EnableTaskManager,
    102                  base::Unretained(this)));
    103   web_ui()->RegisterMessageCallback("disableTaskManager",
    104       base::Bind(&TaskManagerHandler::DisableTaskManager,
    105                  base::Unretained(this)));
    106   web_ui()->RegisterMessageCallback("setUpdateColumn",
    107       base::Bind(&TaskManagerHandler::HandleSetUpdateColumn,
    108                  base::Unretained(this)));
    109 }
    110 
    111 static int parseIndex(const Value* value) {
    112   int index = -1;
    113   string16 string16_index;
    114   double double_index;
    115   if (value->GetAsString(&string16_index)) {
    116     bool converted = base::StringToInt(string16_index, &index);
    117     DCHECK(converted);
    118   } else if (value->GetAsDouble(&double_index)) {
    119     index = static_cast<int>(double_index);
    120   } else {
    121     value->GetAsInteger(&index);
    122   }
    123   return index;
    124 }
    125 
    126 void TaskManagerHandler::HandleKillProcesses(const ListValue* unique_ids) {
    127   for (ListValue::const_iterator i = unique_ids->begin();
    128        i != unique_ids->end(); ++i) {
    129     int unique_id = parseIndex(*i);
    130     int resource_index = model_->GetResourceIndexByUniqueId(unique_id);
    131     if (resource_index == -1)
    132       continue;
    133 
    134     task_manager_->KillProcess(resource_index);
    135   }
    136 }
    137 
    138 void TaskManagerHandler::HandleActivatePage(const ListValue* unique_ids) {
    139   for (ListValue::const_iterator i = unique_ids->begin();
    140        i != unique_ids->end(); ++i) {
    141     int unique_id = parseIndex(*i);
    142     int resource_index = model_->GetResourceIndexByUniqueId(unique_id);
    143     if (resource_index == -1)
    144       continue;
    145 
    146     task_manager_->ActivateProcess(resource_index);
    147     break;
    148   }
    149 }
    150 
    151 void TaskManagerHandler::HandleInspect(const ListValue* unique_ids) {
    152   for (ListValue::const_iterator i = unique_ids->begin();
    153        i != unique_ids->end(); ++i) {
    154     int unique_id = parseIndex(*i);
    155     int resource_index = model_->GetResourceIndexByUniqueId(unique_id);
    156     if (resource_index == -1)
    157       continue;
    158 
    159     if (model_->CanInspect(resource_index))
    160       model_->Inspect(resource_index);
    161     break;
    162   }
    163 }
    164 
    165 void TaskManagerHandler::DisableTaskManager(const ListValue* indexes) {
    166   if (!is_enabled_)
    167     return;
    168 
    169   is_enabled_ = false;
    170   model_->StopUpdating();
    171   model_->RemoveObserver(this);
    172 }
    173 
    174 void TaskManagerHandler::EnableTaskManager(const ListValue* indexes) {
    175   if (is_enabled_)
    176     return;
    177 
    178   is_enabled_ = true;
    179 
    180   OnGroupChanged(0, model_->GroupCount());
    181 
    182   model_->AddObserver(this);
    183   model_->StartUpdating();
    184 }
    185 
    186 void TaskManagerHandler::OpenAboutMemory(const ListValue* indexes) {
    187   content::RenderViewHost* rvh =
    188       web_ui()->GetWebContents()->GetRenderViewHost();
    189   if (rvh) {
    190     WebPreferences webkit_prefs = rvh->GetWebkitPreferences();
    191     webkit_prefs.allow_scripts_to_close_windows = true;
    192     rvh->UpdateWebkitPreferences(webkit_prefs);
    193   } else {
    194     DCHECK(false);
    195   }
    196 
    197   task_manager_->OpenAboutMemory(chrome::GetActiveDesktop());
    198 }
    199 
    200 void TaskManagerHandler::HandleSetUpdateColumn(const ListValue* args) {
    201   DCHECK_EQ(2U, args->GetSize());
    202 
    203   bool ret = true;
    204   std::string column_id;
    205   ret &= args->GetString(0, &column_id);
    206   bool is_enabled;
    207   ret &= args->GetBoolean(1, &is_enabled);
    208   DCHECK(ret);
    209 
    210   if (is_enabled)
    211     enabled_columns_.insert(column_id);
    212   else
    213     enabled_columns_.erase(column_id);
    214 }
    215 
    216 // TaskManagerHandler, private: -----------------------------------------------
    217 
    218 bool TaskManagerHandler::is_alive() {
    219   return web_ui()->GetWebContents()->GetRenderViewHost() != NULL;
    220 }
    221 
    222 void TaskManagerHandler::OnGroupChanged(const int group_start,
    223                                         const int group_length) {
    224   base::FundamentalValue start_value(group_start);
    225   base::FundamentalValue length_value(group_length);
    226   base::ListValue tasks_value;
    227 
    228   for (int i = 0; i < group_length; ++i) {
    229     tasks_value.Append(CreateTaskGroupValue(group_start + i));
    230   }
    231 
    232   if (is_enabled_ && is_alive()) {
    233     web_ui()->CallJavascriptFunction("taskChanged",
    234                                      start_value, length_value, tasks_value);
    235   }
    236 }
    237 
    238 void TaskManagerHandler::OnGroupAdded(const int group_start,
    239                                       const int group_length) {
    240 }
    241 
    242 void TaskManagerHandler::OnGroupRemoved(const int group_start,
    243                                         const int group_length) {
    244 }
    245 
    246 void TaskManagerHandler::OnReadyPeriodicalUpdate() {
    247 }
    248 
    249 base::DictionaryValue* TaskManagerHandler::CreateTaskGroupValue(
    250     int group_index) {
    251   DictionaryValue* val = new DictionaryValue();
    252 
    253   if (group_index >= model_->GroupCount())
    254      return val;
    255 
    256   int index = model_->GetResourceIndexForGroup(group_index, 0);
    257   int length = model_->GetGroupRangeForResource(index).second;
    258 
    259   // Forces to set following column regardless of |enable_columns|.
    260   val->SetInteger("index", index);
    261   CreateGroupColumnList("processId", index, 1, val);
    262   CreateGroupColumnList("type", index, length, val);
    263   CreateGroupColumnList("uniqueId", index, length, val);
    264 
    265   for (size_t i = 0; i < arraysize(kColumnsList); ++i) {
    266     const std::string column_id = kColumnsList[i].column_id;
    267 
    268     if (enabled_columns_.find(column_id) == enabled_columns_.end())
    269       continue;
    270 
    271     int column_length = kColumnsList[i].has_multiple_data ? length : 1;
    272     CreateGroupColumnList(column_id, index, column_length, val);
    273 
    274     if (kColumnsList[i].has_real_value)
    275       CreateGroupColumnList(column_id + "Value", index, column_length, val);
    276   }
    277 
    278   return val;
    279 }
    280 
    281 void TaskManagerHandler::CreateGroupColumnList(const std::string& column_name,
    282                                                const int index,
    283                                                const int length,
    284                                                DictionaryValue* val) {
    285   ListValue* list = new ListValue();
    286   for (int i = index; i < (index + length); ++i) {
    287     list->Append(CreateColumnValue(column_name, i));
    288   }
    289   val->Set(column_name, list);
    290 }
    291 
    292 base::Value* TaskManagerHandler::CreateColumnValue(
    293     const std::string& column_name,
    294     const int i) {
    295   if (column_name == "uniqueId")
    296     return Value::CreateIntegerValue(model_->GetResourceUniqueId(i));
    297   if (column_name == "type") {
    298     return Value::CreateStringValue(
    299         TaskManager::Resource::GetResourceTypeAsString(
    300         model_->GetResourceType(i)));
    301   }
    302   if (column_name == "processId")
    303     return Value::CreateStringValue(model_->GetResourceProcessId(i));
    304   if (column_name == "processIdValue")
    305     return Value::CreateIntegerValue(model_->GetProcessId(i));
    306   if (column_name == "cpuUsage")
    307     return Value::CreateStringValue(model_->GetResourceCPUUsage(i));
    308   if (column_name == "cpuUsageValue")
    309     return Value::CreateDoubleValue(model_->GetCPUUsage(i));
    310   if (column_name == "privateMemory")
    311     return Value::CreateStringValue(model_->GetResourcePrivateMemory(i));
    312   if (column_name == "privateMemoryValue") {
    313     size_t private_memory;
    314     model_->GetPrivateMemory(i, &private_memory);
    315     return Value::CreateDoubleValue(private_memory);
    316   }
    317   if (column_name == "sharedMemory")
    318     return Value::CreateStringValue(model_->GetResourceSharedMemory(i));
    319   if (column_name == "sharedMemoryValue") {
    320     size_t shared_memory;
    321     model_->GetSharedMemory(i, &shared_memory);
    322     return Value::CreateDoubleValue(shared_memory);
    323   }
    324   if (column_name == "physicalMemory")
    325     return Value::CreateStringValue(model_->GetResourcePhysicalMemory(i));
    326   if (column_name == "physicalMemoryValue") {
    327     size_t physical_memory;
    328     model_->GetPhysicalMemory(i, &physical_memory);
    329     return Value::CreateDoubleValue(physical_memory);
    330   }
    331   if (column_name == "icon") {
    332     ui::ScaleFactor icon_scale_factor = web_ui()->GetDeviceScaleFactor();
    333     const gfx::ImageSkia& image = model_->GetResourceIcon(i);
    334     const gfx::ImageSkiaRep image_rep =
    335         image.GetRepresentation(icon_scale_factor);
    336     return Value::CreateStringValue(
    337         webui::GetBitmapDataUrl(image_rep.sk_bitmap()));
    338   }
    339   if (column_name == "title")
    340     return Value::CreateStringValue(model_->GetResourceTitle(i));
    341   if (column_name == "profileName")
    342     return Value::CreateStringValue(model_->GetResourceProfileName(i));
    343   if (column_name == "networkUsage")
    344     return Value::CreateStringValue(model_->GetResourceNetworkUsage(i));
    345   if (column_name == "networkUsageValue")
    346     return Value::CreateDoubleValue(model_->GetNetworkUsage(i));
    347   if (column_name == "webCoreImageCacheSize") {
    348     return Value::CreateStringValue(
    349         model_->GetResourceWebCoreImageCacheSize(i));
    350   }
    351   if (column_name == "webCoreImageCacheSizeValue") {
    352     WebKit::WebCache::ResourceTypeStats resource_stats;
    353     model_->GetWebCoreCacheStats(i, &resource_stats);
    354     return Value::CreateDoubleValue(resource_stats.images.size);
    355   }
    356   if (column_name == "webCoreScriptsCacheSize") {
    357     return Value::CreateStringValue(
    358         model_->GetResourceWebCoreScriptsCacheSize(i));
    359   }
    360   if (column_name == "webCoreScriptsCacheSizeValue") {
    361     WebKit::WebCache::ResourceTypeStats resource_stats;
    362     model_->GetWebCoreCacheStats(i, &resource_stats);
    363     return Value::CreateDoubleValue(resource_stats.scripts.size);
    364   }
    365   if (column_name == "webCoreCSSCacheSize")
    366     return Value::CreateStringValue(model_->GetResourceWebCoreCSSCacheSize(i));
    367   if (column_name == "webCoreCSSCacheSizeValue") {
    368     WebKit::WebCache::ResourceTypeStats resource_stats;
    369     model_->GetWebCoreCacheStats(i, &resource_stats);
    370     return Value::CreateDoubleValue(resource_stats.cssStyleSheets.size);
    371   }
    372   if (column_name == "fps")
    373     return Value::CreateStringValue(model_->GetResourceFPS(i));
    374   if (column_name == "fpsValue") {
    375     float fps;
    376     model_->GetFPS(i, &fps);
    377     return Value::CreateDoubleValue(fps);
    378   }
    379   if (column_name == "videoMemory")
    380     return Value::CreateStringValue(model_->GetResourceVideoMemory(i));
    381   if (column_name == "videoMemoryValue") {
    382     size_t video_memory;
    383     bool has_duplicates;
    384     double value;
    385     if (model_->GetVideoMemory(i, &video_memory, &has_duplicates))
    386       value = static_cast<double>(video_memory);
    387     else
    388       value = 0;
    389     return Value::CreateDoubleValue(value);
    390   }
    391   if (column_name == "sqliteMemoryUsed")
    392     return Value::CreateStringValue(model_->GetResourceSqliteMemoryUsed(i));
    393   if (column_name == "sqliteMemoryUsedValue") {
    394     size_t sqlite_memory;
    395     model_->GetSqliteMemoryUsedBytes(i, &sqlite_memory);
    396     return Value::CreateDoubleValue(sqlite_memory);
    397   }
    398   if (column_name == "goatsTeleported")
    399     return Value::CreateStringValue(model_->GetResourceGoatsTeleported(i));
    400   if (column_name == "goatsTeleportedValue")
    401     return Value::CreateIntegerValue(model_->GetGoatsTeleported(i));
    402   if (column_name == "v8MemoryAllocatedSize") {
    403     return Value::CreateStringValue(
    404         model_->GetResourceV8MemoryAllocatedSize(i));
    405   }
    406   if (column_name == "v8MemoryAllocatedSizeValue") {
    407     size_t v8_memory;
    408     model_->GetV8Memory(i, &v8_memory);
    409     return Value::CreateDoubleValue(v8_memory);
    410   }
    411   if (column_name == "canInspect")
    412     return Value::CreateBooleanValue(model_->CanInspect(i));
    413   if (column_name == "canActivate")
    414     return Value::CreateBooleanValue(model_->CanActivate(i));
    415 
    416   NOTREACHED();
    417   return NULL;
    418 }
    419