Home | History | Annotate | Download | only in processes
      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/extensions/api/processes/processes_api.h"
      6 
      7 #include "base/callback.h"
      8 #include "base/json/json_writer.h"
      9 #include "base/lazy_instance.h"
     10 #include "base/message_loop/message_loop.h"
     11 #include "base/metrics/histogram.h"
     12 #include "base/strings/string_number_conversions.h"
     13 #include "base/strings/utf_string_conversions.h"
     14 #include "base/values.h"
     15 #include "chrome/browser/chrome_notification_types.h"
     16 #include "chrome/browser/extensions/api/processes/processes_api_constants.h"
     17 #include "chrome/browser/extensions/api/tabs/tabs_constants.h"
     18 #include "chrome/browser/extensions/event_router.h"
     19 #include "chrome/browser/extensions/extension_function_registry.h"
     20 #include "chrome/browser/extensions/extension_function_util.h"
     21 #include "chrome/browser/extensions/extension_service.h"
     22 #include "chrome/browser/extensions/extension_system.h"
     23 #include "chrome/browser/extensions/extension_tab_util.h"
     24 #include "chrome/browser/profiles/profile.h"
     25 #include "chrome/browser/task_manager/resource_provider.h"
     26 #include "chrome/browser/task_manager/task_manager.h"
     27 #include "content/public/browser/notification_details.h"
     28 #include "content/public/browser/notification_service.h"
     29 #include "content/public/browser/notification_source.h"
     30 #include "content/public/browser/notification_types.h"
     31 #include "content/public/browser/render_process_host.h"
     32 #include "content/public/browser/render_view_host.h"
     33 #include "content/public/browser/render_widget_host.h"
     34 #include "content/public/browser/web_contents.h"
     35 #include "content/public/common/result_codes.h"
     36 #include "extensions/common/error_utils.h"
     37 
     38 namespace extensions {
     39 
     40 namespace keys = processes_api_constants;
     41 namespace errors = processes_api_constants;
     42 
     43 namespace {
     44 
     45 #if defined(ENABLE_TASK_MANAGER)
     46 
     47 base::DictionaryValue* CreateCacheData(
     48     const WebKit::WebCache::ResourceTypeStat& stat) {
     49 
     50   base::DictionaryValue* cache = new base::DictionaryValue();
     51   cache->SetDouble(keys::kCacheSize, static_cast<double>(stat.size));
     52   cache->SetDouble(keys::kCacheLiveSize, static_cast<double>(stat.liveSize));
     53   return cache;
     54 }
     55 
     56 void SetProcessType(base::DictionaryValue* result,
     57                     TaskManagerModel* model,
     58                     int index) {
     59   // Determine process type.
     60   std::string type = keys::kProcessTypeOther;
     61   task_manager::Resource::Type resource_type = model->GetResourceType(index);
     62   switch (resource_type) {
     63     case task_manager::Resource::BROWSER:
     64       type = keys::kProcessTypeBrowser;
     65       break;
     66     case task_manager::Resource::RENDERER:
     67       type = keys::kProcessTypeRenderer;
     68       break;
     69     case task_manager::Resource::EXTENSION:
     70       type = keys::kProcessTypeExtension;
     71       break;
     72     case task_manager::Resource::NOTIFICATION:
     73       type = keys::kProcessTypeNotification;
     74       break;
     75     case task_manager::Resource::PLUGIN:
     76       type = keys::kProcessTypePlugin;
     77       break;
     78     case task_manager::Resource::WORKER:
     79       type = keys::kProcessTypeWorker;
     80       break;
     81     case task_manager::Resource::NACL:
     82       type = keys::kProcessTypeNacl;
     83       break;
     84     case task_manager::Resource::UTILITY:
     85       type = keys::kProcessTypeUtility;
     86       break;
     87     case task_manager::Resource::GPU:
     88       type = keys::kProcessTypeGPU;
     89       break;
     90     case task_manager::Resource::ZYGOTE:
     91     case task_manager::Resource::SANDBOX_HELPER:
     92     case task_manager::Resource::UNKNOWN:
     93       type = keys::kProcessTypeOther;
     94       break;
     95     default:
     96       NOTREACHED() << "Unknown resource type.";
     97   }
     98   result->SetString(keys::kTypeKey, type);
     99 }
    100 
    101 base::ListValue* GetTabsForProcess(int process_id) {
    102   base::ListValue* tabs_list = new base::ListValue();
    103 
    104   // The tabs list only makes sense for render processes, so if we don't find
    105   // one, just return the empty list.
    106   content::RenderProcessHost* rph =
    107       content::RenderProcessHost::FromID(process_id);
    108   if (rph == NULL)
    109     return tabs_list;
    110 
    111   int tab_id = -1;
    112   // We need to loop through all the RVHs to ensure we collect the set of all
    113   // tabs using this renderer process.
    114   content::RenderWidgetHost::List widgets =
    115       content::RenderWidgetHost::GetRenderWidgetHosts();
    116   for (size_t i = 0; i < widgets.size(); ++i) {
    117     if (widgets[i]->GetProcess()->GetID() != process_id)
    118       continue;
    119     if (!widgets[i]->IsRenderView())
    120       continue;
    121 
    122     content::RenderViewHost* host = content::RenderViewHost::From(widgets[i]);
    123     content::WebContents* contents =
    124         content::WebContents::FromRenderViewHost(host);
    125     if (contents) {
    126       tab_id = ExtensionTabUtil::GetTabId(contents);
    127       if (tab_id != -1)
    128         tabs_list->Append(Value::CreateIntegerValue(tab_id));
    129     }
    130   }
    131 
    132   return tabs_list;
    133 }
    134 
    135 // This function creates a Process object to be returned to the extensions
    136 // using these APIs. For memory details, which are not added by this function,
    137 // the callers need to use AddMemoryDetails.
    138 base::DictionaryValue* CreateProcessFromModel(int process_id,
    139                                               TaskManagerModel* model,
    140                                               int index,
    141                                               bool include_optional) {
    142   base::DictionaryValue* result = new base::DictionaryValue();
    143   size_t mem;
    144 
    145   result->SetInteger(keys::kIdKey, process_id);
    146   result->SetInteger(keys::kOsProcessIdKey, model->GetProcessId(index));
    147   SetProcessType(result, model, index);
    148   result->SetString(keys::kProfileKey,
    149       model->GetResourceProfileName(index));
    150 
    151   result->Set(keys::kTabsListKey, GetTabsForProcess(process_id));
    152 
    153   // If we don't need to include the optional properties, just return now.
    154   if (!include_optional)
    155     return result;
    156 
    157   result->SetDouble(keys::kCpuKey, model->GetCPUUsage(index));
    158 
    159   if (model->GetV8Memory(index, &mem))
    160     result->SetDouble(keys::kJsMemoryAllocatedKey,
    161         static_cast<double>(mem));
    162 
    163   if (model->GetV8MemoryUsed(index, &mem))
    164     result->SetDouble(keys::kJsMemoryUsedKey,
    165         static_cast<double>(mem));
    166 
    167   if (model->GetSqliteMemoryUsedBytes(index, &mem))
    168     result->SetDouble(keys::kSqliteMemoryKey,
    169         static_cast<double>(mem));
    170 
    171   WebKit::WebCache::ResourceTypeStats cache_stats;
    172   if (model->GetWebCoreCacheStats(index, &cache_stats)) {
    173     result->Set(keys::kImageCacheKey,
    174                 CreateCacheData(cache_stats.images));
    175     result->Set(keys::kScriptCacheKey,
    176                 CreateCacheData(cache_stats.scripts));
    177     result->Set(keys::kCssCacheKey,
    178                 CreateCacheData(cache_stats.cssStyleSheets));
    179   }
    180 
    181   // Network and FPS are reported by the TaskManager per resource (tab), not
    182   // per process, therefore we need to iterate through the group of resources
    183   // and aggregate the data.
    184   float fps = 0, tmp = 0;
    185   int64 net = 0;
    186   int length = model->GetGroupRangeForResource(index).second;
    187   for (int i = 0; i < length; ++i) {
    188     net += model->GetNetworkUsage(index + i);
    189     if (model->GetFPS(index + i, &tmp))
    190       fps += tmp;
    191   }
    192   result->SetDouble(keys::kFPSKey, static_cast<double>(fps));
    193   result->SetDouble(keys::kNetworkKey, static_cast<double>(net));
    194 
    195   return result;
    196 }
    197 
    198 // Since memory details are expensive to gather, we don't do it by default.
    199 // This function is a helper to add memory details data to an existing
    200 // Process object representation.
    201 void AddMemoryDetails(base::DictionaryValue* result,
    202                       TaskManagerModel* model,
    203                       int index) {
    204   size_t mem;
    205   int64 pr_mem = model->GetPrivateMemory(index, &mem) ?
    206       static_cast<int64>(mem) : -1;
    207   result->SetDouble(keys::kPrivateMemoryKey, static_cast<double>(pr_mem));
    208 }
    209 
    210 #endif  // defined(ENABLE_TASK_MANAGER)
    211 
    212 }  // namespace
    213 
    214 ProcessesEventRouter::ProcessesEventRouter(Profile* profile)
    215     : profile_(profile),
    216       listeners_(0),
    217       task_manager_listening_(false) {
    218 #if defined(ENABLE_TASK_MANAGER)
    219   model_ = TaskManager::GetInstance()->model();
    220   model_->AddObserver(this);
    221 
    222   registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_HANG,
    223       content::NotificationService::AllSources());
    224   registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
    225       content::NotificationService::AllSources());
    226 #endif  // defined(ENABLE_TASK_MANAGER)
    227 }
    228 
    229 ProcessesEventRouter::~ProcessesEventRouter() {
    230 #if defined(ENABLE_TASK_MANAGER)
    231   registrar_.Remove(this, content::NOTIFICATION_RENDERER_PROCESS_HANG,
    232       content::NotificationService::AllSources());
    233   registrar_.Remove(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
    234       content::NotificationService::AllSources());
    235 
    236   if (task_manager_listening_)
    237     model_->StopListening();
    238 
    239   model_->RemoveObserver(this);
    240 #endif  // defined(ENABLE_TASK_MANAGER)
    241 }
    242 
    243 void ProcessesEventRouter::ListenerAdded() {
    244 #if defined(ENABLE_TASK_MANAGER)
    245   // The task manager has its own ref count to balance other callers of
    246   // StartUpdating/StopUpdating.
    247   model_->StartUpdating();
    248 #endif  // defined(ENABLE_TASK_MANAGER)
    249   ++listeners_;
    250 }
    251 
    252 void ProcessesEventRouter::ListenerRemoved() {
    253   DCHECK_GT(listeners_, 0);
    254   --listeners_;
    255 #if defined(ENABLE_TASK_MANAGER)
    256   // The task manager has its own ref count to balance other callers of
    257   // StartUpdating/StopUpdating.
    258   model_->StopUpdating();
    259 #endif  // defined(ENABLE_TASK_MANAGER)
    260 }
    261 
    262 void ProcessesEventRouter::StartTaskManagerListening() {
    263 #if defined(ENABLE_TASK_MANAGER)
    264   if (!task_manager_listening_) {
    265     model_->StartListening();
    266     task_manager_listening_ = true;
    267   }
    268 #endif  // defined(ENABLE_TASK_MANAGER)
    269 }
    270 
    271 void ProcessesEventRouter::Observe(
    272     int type,
    273     const content::NotificationSource& source,
    274     const content::NotificationDetails& details) {
    275 
    276   switch (type) {
    277     case content::NOTIFICATION_RENDERER_PROCESS_HANG:
    278       ProcessHangEvent(
    279           content::Source<content::RenderWidgetHost>(source).ptr());
    280       break;
    281     case content::NOTIFICATION_RENDERER_PROCESS_CLOSED:
    282       ProcessClosedEvent(
    283           content::Source<content::RenderProcessHost>(source).ptr(),
    284           content::Details<content::RenderProcessHost::RendererClosedDetails>(
    285               details).ptr());
    286       break;
    287     default:
    288       NOTREACHED() << "Unexpected observe of type " << type;
    289   }
    290   return;
    291 }
    292 
    293 void ProcessesEventRouter::OnItemsAdded(int start, int length) {
    294 #if defined(ENABLE_TASK_MANAGER)
    295   DCHECK_EQ(length, 1);
    296   int index = start;
    297 
    298   std::string event(keys::kOnCreated);
    299   if (!HasEventListeners(event))
    300     return;
    301 
    302   // If the item being added is not the first one in the group, find the base
    303   // index and use it for retrieving the process data.
    304   if (!model_->IsResourceFirstInGroup(start)) {
    305     index = model_->GetGroupIndexForResource(start);
    306   }
    307 
    308   scoped_ptr<base::ListValue> args(new base::ListValue());
    309   base::DictionaryValue* process = CreateProcessFromModel(
    310       model_->GetUniqueChildProcessId(index), model_, index, false);
    311   DCHECK(process != NULL);
    312 
    313   if (process == NULL)
    314     return;
    315 
    316   args->Append(process);
    317 
    318   DispatchEvent(keys::kOnCreated, args.Pass());
    319 #endif  // defined(ENABLE_TASK_MANAGER)
    320 }
    321 
    322 void ProcessesEventRouter::OnItemsChanged(int start, int length) {
    323 #if defined(ENABLE_TASK_MANAGER)
    324   // If we don't have any listeners, return immediately.
    325   if (listeners_ == 0)
    326     return;
    327 
    328   if (!model_)
    329     return;
    330 
    331   // We need to know which type of onUpdated events to fire and whether to
    332   // collect memory or not.
    333   std::string updated_event(keys::kOnUpdated);
    334   std::string updated_event_memory(keys::kOnUpdatedWithMemory);
    335   bool updated = HasEventListeners(updated_event);
    336   bool updated_memory = HasEventListeners(updated_event_memory);
    337 
    338   DCHECK(updated || updated_memory);
    339 
    340   IDMap<base::DictionaryValue> processes_map;
    341   for (int i = start; i < start + length; i++) {
    342     if (model_->IsResourceFirstInGroup(i)) {
    343       int id = model_->GetUniqueChildProcessId(i);
    344       base::DictionaryValue* process = CreateProcessFromModel(id, model_, i, true);
    345       processes_map.AddWithID(process, i);
    346     }
    347   }
    348 
    349   int id;
    350   std::string idkey(keys::kIdKey);
    351   base::DictionaryValue* processes = new base::DictionaryValue();
    352 
    353   if (updated) {
    354     IDMap<base::DictionaryValue>::iterator it(&processes_map);
    355     for (; !it.IsAtEnd(); it.Advance()) {
    356       if (!it.GetCurrentValue()->GetInteger(idkey, &id))
    357         continue;
    358 
    359       // Store each process indexed by the string version of its id.
    360       processes->Set(base::IntToString(id), it.GetCurrentValue());
    361     }
    362 
    363     scoped_ptr<base::ListValue> args(new base::ListValue());
    364     args->Append(processes);
    365     DispatchEvent(keys::kOnUpdated, args.Pass());
    366   }
    367 
    368   if (updated_memory) {
    369     IDMap<base::DictionaryValue>::iterator it(&processes_map);
    370     for (; !it.IsAtEnd(); it.Advance()) {
    371       if (!it.GetCurrentValue()->GetInteger(idkey, &id))
    372         continue;
    373 
    374       AddMemoryDetails(it.GetCurrentValue(), model_, it.GetCurrentKey());
    375 
    376       // Store each process indexed by the string version of its id if we didn't
    377       // already insert it as part of the onUpdated processing above.
    378       if (!updated)
    379         processes->Set(base::IntToString(id), it.GetCurrentValue());
    380     }
    381 
    382     scoped_ptr<base::ListValue> args(new base::ListValue());
    383     args->Append(processes);
    384     DispatchEvent(keys::kOnUpdatedWithMemory, args.Pass());
    385   }
    386 #endif  // defined(ENABLE_TASK_MANAGER)
    387 }
    388 
    389 void ProcessesEventRouter::OnItemsToBeRemoved(int start, int length) {
    390 #if defined(ENABLE_TASK_MANAGER)
    391   DCHECK_EQ(length, 1);
    392 
    393   // Process exit for renderer processes has the data about exit code and
    394   // termination status, therefore we will rely on notifications and not on
    395   // the Task Manager data. We do use the rest of this method for non-renderer
    396   // processes.
    397   if (model_->GetResourceType(start) == task_manager::Resource::RENDERER)
    398     return;
    399 
    400   // The callback function parameters.
    401   scoped_ptr<base::ListValue> args(new base::ListValue());
    402 
    403   // First arg: The id of the process that was closed.
    404   args->Append(Value::CreateIntegerValue(
    405       model_->GetUniqueChildProcessId(start)));
    406 
    407   // Second arg: The exit type for the process.
    408   args->Append(Value::CreateIntegerValue(0));
    409 
    410   // Third arg: The exit code for the process.
    411   args->Append(Value::CreateIntegerValue(0));
    412 
    413   DispatchEvent(keys::kOnExited, args.Pass());
    414 #endif  // defined(ENABLE_TASK_MANAGER)
    415 }
    416 
    417 void ProcessesEventRouter::ProcessHangEvent(content::RenderWidgetHost* widget) {
    418 #if defined(ENABLE_TASK_MANAGER)
    419   std::string event(keys::kOnUnresponsive);
    420   if (!HasEventListeners(event))
    421     return;
    422 
    423   base::DictionaryValue* process = NULL;
    424   int count = model_->ResourceCount();
    425   int id = widget->GetProcess()->GetID();
    426 
    427   for (int i = 0; i < count; ++i) {
    428     if (model_->IsResourceFirstInGroup(i)) {
    429       if (id == model_->GetUniqueChildProcessId(i)) {
    430         process = CreateProcessFromModel(id, model_, i, false);
    431         break;
    432       }
    433     }
    434   }
    435 
    436   DCHECK(process);
    437   if (process == NULL)
    438     return;
    439 
    440   scoped_ptr<base::ListValue> args(new base::ListValue());
    441   args->Append(process);
    442 
    443   DispatchEvent(keys::kOnUnresponsive, args.Pass());
    444 #endif  // defined(ENABLE_TASK_MANAGER)
    445 }
    446 
    447 void ProcessesEventRouter::ProcessClosedEvent(
    448     content::RenderProcessHost* rph,
    449     content::RenderProcessHost::RendererClosedDetails* details) {
    450 #if defined(ENABLE_TASK_MANAGER)
    451   // The callback function parameters.
    452   scoped_ptr<base::ListValue> args(new base::ListValue());
    453 
    454   // First arg: The id of the process that was closed.
    455   args->Append(Value::CreateIntegerValue(rph->GetID()));
    456 
    457   // Second arg: The exit type for the process.
    458   args->Append(Value::CreateIntegerValue(details->status));
    459 
    460   // Third arg: The exit code for the process.
    461   args->Append(Value::CreateIntegerValue(details->exit_code));
    462 
    463   DispatchEvent(keys::kOnExited, args.Pass());
    464 #endif  // defined(ENABLE_TASK_MANAGER)
    465 }
    466 
    467 void ProcessesEventRouter::DispatchEvent(
    468     const char* event_name,
    469     scoped_ptr<base::ListValue> event_args) {
    470   if (extensions::ExtensionSystem::Get(profile_)->event_router()) {
    471     scoped_ptr<extensions::Event> event(new extensions::Event(
    472         event_name, event_args.Pass()));
    473     extensions::ExtensionSystem::Get(profile_)->event_router()->
    474         BroadcastEvent(event.Pass());
    475   }
    476 }
    477 
    478 bool ProcessesEventRouter::HasEventListeners(const std::string& event_name) {
    479   extensions::EventRouter* router =
    480       extensions::ExtensionSystem::Get(profile_)->event_router();
    481   if (router && router->HasEventListener(event_name))
    482     return true;
    483   return false;
    484 }
    485 
    486 ProcessesAPI::ProcessesAPI(Profile* profile) : profile_(profile) {
    487   ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
    488       this, processes_api_constants::kOnUpdated);
    489   ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
    490       this, processes_api_constants::kOnUpdatedWithMemory);
    491   ExtensionFunctionRegistry* registry =
    492       ExtensionFunctionRegistry::GetInstance();
    493   registry->RegisterFunction<extensions::GetProcessIdForTabFunction>();
    494   registry->RegisterFunction<extensions::TerminateFunction>();
    495   registry->RegisterFunction<extensions::GetProcessInfoFunction>();
    496 }
    497 
    498 ProcessesAPI::~ProcessesAPI() {
    499 }
    500 
    501 void ProcessesAPI::Shutdown() {
    502   ExtensionSystem::Get(profile_)->event_router()->UnregisterObserver(this);
    503 }
    504 
    505 static base::LazyInstance<ProfileKeyedAPIFactory<ProcessesAPI> >
    506 g_factory = LAZY_INSTANCE_INITIALIZER;
    507 
    508 // static
    509 ProfileKeyedAPIFactory<ProcessesAPI>* ProcessesAPI::GetFactoryInstance() {
    510   return &g_factory.Get();
    511 }
    512 
    513 // static
    514 ProcessesAPI* ProcessesAPI::Get(Profile* profile) {
    515   return ProfileKeyedAPIFactory<ProcessesAPI>::GetForProfile(profile);
    516 }
    517 
    518 ProcessesEventRouter* ProcessesAPI::processes_event_router() {
    519   if (!processes_event_router_)
    520     processes_event_router_.reset(new ProcessesEventRouter(profile_));
    521   return processes_event_router_.get();
    522 }
    523 
    524 void ProcessesAPI::OnListenerAdded(const EventListenerInfo& details) {
    525   // We lazily tell the TaskManager to start updating when listeners to the
    526   // processes.onUpdated or processes.onUpdatedWithMemory events arrive.
    527   processes_event_router()->ListenerAdded();
    528 }
    529 
    530 void ProcessesAPI::OnListenerRemoved(const EventListenerInfo& details) {
    531   // If a processes.onUpdated or processes.onUpdatedWithMemory event listener
    532   // is removed (or a process with one exits), then we let the extension API
    533   // know that it has one fewer listener.
    534   processes_event_router()->ListenerRemoved();
    535 }
    536 
    537 GetProcessIdForTabFunction::GetProcessIdForTabFunction() : tab_id_(-1) {
    538 }
    539 
    540 bool GetProcessIdForTabFunction::RunImpl() {
    541 #if defined(ENABLE_TASK_MANAGER)
    542   EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &tab_id_));
    543 
    544   // Add a reference, which is balanced in GetProcessIdForTab to keep the object
    545   // around and allow for the callback to be invoked.
    546   AddRef();
    547 
    548   // If the task manager is already listening, just post a task to execute
    549   // which will invoke the callback once we have returned from this function.
    550   // Otherwise, wait for the notification that the task manager is done with
    551   // the data gathering.
    552   if (ProcessesAPI::Get(profile_)->processes_event_router()->
    553       is_task_manager_listening()) {
    554     base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
    555         &GetProcessIdForTabFunction::GetProcessIdForTab, this));
    556   } else {
    557     registrar_.Add(this,
    558                    chrome::NOTIFICATION_TASK_MANAGER_CHILD_PROCESSES_DATA_READY,
    559                    content::NotificationService::AllSources());
    560     ProcessesAPI::Get(profile_)->processes_event_router()->
    561         StartTaskManagerListening();
    562   }
    563 
    564   return true;
    565 #else
    566   error_ = errors::kExtensionNotSupported;
    567   return false;
    568 #endif  // defined(ENABLE_TASK_MANAGER)
    569 }
    570 
    571 void GetProcessIdForTabFunction::Observe(
    572     int type,
    573     const content::NotificationSource& source,
    574     const content::NotificationDetails& details) {
    575   DCHECK_EQ(type, chrome::NOTIFICATION_TASK_MANAGER_CHILD_PROCESSES_DATA_READY);
    576   registrar_.RemoveAll();
    577   GetProcessIdForTab();
    578 }
    579 
    580 void GetProcessIdForTabFunction::GetProcessIdForTab() {
    581   content::WebContents* contents = NULL;
    582   int tab_index = -1;
    583   if (!ExtensionTabUtil::GetTabById(tab_id_, profile(), include_incognito(),
    584                                     NULL, NULL, &contents, &tab_index)) {
    585     error_ = ErrorUtils::FormatErrorMessage(
    586         extensions::tabs_constants::kTabNotFoundError,
    587         base::IntToString(tab_id_));
    588     SetResult(Value::CreateIntegerValue(-1));
    589     SendResponse(false);
    590   } else {
    591     int process_id = contents->GetRenderProcessHost()->GetID();
    592     SetResult(Value::CreateIntegerValue(process_id));
    593     SendResponse(true);
    594   }
    595 
    596   // Balance the AddRef in the RunImpl.
    597   Release();
    598 }
    599 
    600 TerminateFunction::TerminateFunction() : process_id_(-1) {
    601 }
    602 
    603 bool TerminateFunction::RunImpl() {
    604 #if defined(ENABLE_TASK_MANAGER)
    605   EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &process_id_));
    606 
    607   // Add a reference, which is balanced in TerminateProcess to keep the object
    608   // around and allow for the callback to be invoked.
    609   AddRef();
    610 
    611   // If the task manager is already listening, just post a task to execute
    612   // which will invoke the callback once we have returned from this function.
    613   // Otherwise, wait for the notification that the task manager is done with
    614   // the data gathering.
    615   if (ProcessesAPI::Get(profile_)->processes_event_router()->
    616       is_task_manager_listening()) {
    617     base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
    618         &TerminateFunction::TerminateProcess, this));
    619   } else {
    620     registrar_.Add(this,
    621                    chrome::NOTIFICATION_TASK_MANAGER_CHILD_PROCESSES_DATA_READY,
    622                    content::NotificationService::AllSources());
    623     ProcessesAPI::Get(profile_)->processes_event_router()->
    624         StartTaskManagerListening();
    625   }
    626 
    627   return true;
    628 #else
    629   error_ = errors::kExtensionNotSupported;
    630   return false;
    631 #endif  // defined(ENABLE_TASK_MANAGER)
    632 }
    633 
    634 void TerminateFunction::Observe(
    635     int type,
    636     const content::NotificationSource& source,
    637     const content::NotificationDetails& details) {
    638   DCHECK_EQ(type, chrome::NOTIFICATION_TASK_MANAGER_CHILD_PROCESSES_DATA_READY);
    639   registrar_.RemoveAll();
    640   TerminateProcess();
    641 }
    642 
    643 void TerminateFunction::TerminateProcess() {
    644   TaskManagerModel* model = TaskManager::GetInstance()->model();
    645 
    646   int count = model->ResourceCount();
    647   bool killed = false;
    648   bool found = false;
    649 
    650   for (int i = 0; i < count; ++i) {
    651     if (model->IsResourceFirstInGroup(i)) {
    652       if (process_id_ == model->GetUniqueChildProcessId(i)) {
    653         found = true;
    654         killed = base::KillProcess(model->GetProcess(i),
    655             content::RESULT_CODE_KILLED, true);
    656         UMA_HISTOGRAM_COUNTS("ChildProcess.KilledByExtensionAPI", 1);
    657         break;
    658       }
    659     }
    660   }
    661 
    662   if (!found) {
    663     error_ = ErrorUtils::FormatErrorMessage(errors::kProcessNotFound,
    664         base::IntToString(process_id_));
    665     SendResponse(false);
    666   } else {
    667     SetResult(Value::CreateBooleanValue(killed));
    668     SendResponse(true);
    669   }
    670 
    671   // Balance the AddRef in the RunImpl.
    672   Release();
    673 }
    674 
    675 GetProcessInfoFunction::GetProcessInfoFunction()
    676 #if defined(ENABLE_TASK_MANAGER)
    677   : memory_(false)
    678 #endif
    679     {
    680 }
    681 
    682 GetProcessInfoFunction::~GetProcessInfoFunction() {
    683 }
    684 
    685 bool GetProcessInfoFunction::RunImpl() {
    686 #if defined(ENABLE_TASK_MANAGER)
    687   Value* processes = NULL;
    688 
    689   EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &processes));
    690   EXTENSION_FUNCTION_VALIDATE(args_->GetBoolean(1, &memory_));
    691 
    692   EXTENSION_FUNCTION_VALIDATE(extensions::ReadOneOrMoreIntegers(
    693       processes, &process_ids_));
    694 
    695   // Add a reference, which is balanced in GatherProcessInfo to keep the object
    696   // around and allow for the callback to be invoked.
    697   AddRef();
    698 
    699   // If the task manager is already listening, just post a task to execute
    700   // which will invoke the callback once we have returned from this function.
    701   // Otherwise, wait for the notification that the task manager is done with
    702   // the data gathering.
    703   if (ProcessesAPI::Get(profile_)->processes_event_router()->
    704       is_task_manager_listening()) {
    705     base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
    706         &GetProcessInfoFunction::GatherProcessInfo, this));
    707   } else {
    708     registrar_.Add(this,
    709                    chrome::NOTIFICATION_TASK_MANAGER_CHILD_PROCESSES_DATA_READY,
    710                    content::NotificationService::AllSources());
    711     ProcessesAPI::Get(profile_)->processes_event_router()->
    712         StartTaskManagerListening();
    713   }
    714   return true;
    715 
    716 #else
    717   error_ = errors::kExtensionNotSupported;
    718   return false;
    719 #endif  // defined(ENABLE_TASK_MANAGER)
    720 }
    721 
    722 void GetProcessInfoFunction::Observe(
    723     int type,
    724     const content::NotificationSource& source,
    725     const content::NotificationDetails& details) {
    726   DCHECK_EQ(type, chrome::NOTIFICATION_TASK_MANAGER_CHILD_PROCESSES_DATA_READY);
    727   registrar_.RemoveAll();
    728   GatherProcessInfo();
    729 }
    730 
    731 void GetProcessInfoFunction::GatherProcessInfo() {
    732 #if defined(ENABLE_TASK_MANAGER)
    733   TaskManagerModel* model = TaskManager::GetInstance()->model();
    734   base::DictionaryValue* processes = new base::DictionaryValue();
    735 
    736   // If there are no process IDs specified, it means we need to return all of
    737   // the ones we know of.
    738   if (process_ids_.size() == 0) {
    739     int resources = model->ResourceCount();
    740     for (int i = 0; i < resources; ++i) {
    741       if (model->IsResourceFirstInGroup(i)) {
    742         int id = model->GetUniqueChildProcessId(i);
    743         base::DictionaryValue* d = CreateProcessFromModel(id, model, i, false);
    744         if (memory_)
    745           AddMemoryDetails(d, model, i);
    746         processes->Set(base::IntToString(id), d);
    747       }
    748     }
    749   } else {
    750     int resources = model->ResourceCount();
    751     for (int i = 0; i < resources; ++i) {
    752       if (model->IsResourceFirstInGroup(i)) {
    753         int id = model->GetUniqueChildProcessId(i);
    754         std::vector<int>::iterator proc_id = std::find(process_ids_.begin(),
    755                                                        process_ids_.end(), id);
    756         if (proc_id != process_ids_.end()) {
    757           base::DictionaryValue* d =
    758               CreateProcessFromModel(id, model, i, false);
    759           if (memory_)
    760             AddMemoryDetails(d, model, i);
    761           processes->Set(base::IntToString(id), d);
    762 
    763           process_ids_.erase(proc_id);
    764           if (process_ids_.size() == 0)
    765             break;
    766         }
    767       }
    768     }
    769     DCHECK_EQ(process_ids_.size(), 0U);
    770   }
    771 
    772   SetResult(processes);
    773   SendResponse(true);
    774 
    775   // Balance the AddRef in the RunImpl.
    776   Release();
    777 #endif  // defined(ENABLE_TASK_MANAGER)
    778 }
    779 
    780 }  // namespace extensions
    781