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