Remove some NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED from c/b/extensions Part2
[chromium-blink-merge.git] / chrome / browser / extensions / api / processes / processes_api.cc
blob70bc204131a1ec52cb9b359621b217d6be9e34a9
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.
5 #include "chrome/browser/extensions/api/processes/processes_api.h"
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"
39 namespace extensions {
41 namespace keys = processes_api_constants;
42 namespace errors = processes_api_constants;
44 namespace {
46 #if defined(ENABLE_TASK_MANAGER)
48 base::DictionaryValue* CreateCacheData(
49 const blink::WebCache::ResourceTypeStat& stat) {
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;
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.";
99 result->SetString(keys::kTypeKey, type);
102 base::ListValue* GetTabsForProcess(int process_id) {
103 base::ListValue* tabs_list = new base::ListValue();
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;
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;
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));
133 return tabs_list;
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;
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));
155 result->Set(keys::kTabsListKey, GetTabsForProcess(process_id));
157 // If we don't need to include the optional properties, just return now.
158 if (!include_optional)
159 return result;
161 result->SetDouble(keys::kCpuKey, model->GetCPUUsage(index));
163 if (model->GetV8Memory(index, &mem))
164 result->SetDouble(keys::kJsMemoryAllocatedKey,
165 static_cast<double>(mem));
167 if (model->GetV8MemoryUsed(index, &mem))
168 result->SetDouble(keys::kJsMemoryUsedKey,
169 static_cast<double>(mem));
171 if (model->GetSqliteMemoryUsedBytes(index, &mem))
172 result->SetDouble(keys::kSqliteMemoryKey,
173 static_cast<double>(mem));
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));
185 // Network and FPS are reported by the TaskManager per resource (tab), not
186 // per process, therefore we need to iterate through the group of resources
187 // and aggregate the data.
188 float fps = 0, tmp = 0;
189 int64 net = 0;
190 int length = model->GetGroupRangeForResource(index).second;
191 for (int i = 0; i < length; ++i) {
192 net += model->GetNetworkUsage(index + i);
193 if (model->GetFPS(index + i, &tmp))
194 fps += tmp;
196 result->SetDouble(keys::kFPSKey, static_cast<double>(fps));
197 result->SetDouble(keys::kNetworkKey, static_cast<double>(net));
199 return result;
202 // Since memory details are expensive to gather, we don't do it by default.
203 // This function is a helper to add memory details data to an existing
204 // Process object representation.
205 void AddMemoryDetails(base::DictionaryValue* result,
206 TaskManagerModel* model,
207 int index) {
208 size_t mem;
209 int64 pr_mem = model->GetPrivateMemory(index, &mem) ?
210 static_cast<int64>(mem) : -1;
211 result->SetDouble(keys::kPrivateMemoryKey, static_cast<double>(pr_mem));
214 #endif // defined(ENABLE_TASK_MANAGER)
216 } // namespace
218 ProcessesEventRouter::ProcessesEventRouter(content::BrowserContext* context)
219 : browser_context_(context), listeners_(0), task_manager_listening_(false) {
220 #if defined(ENABLE_TASK_MANAGER)
221 model_ = TaskManager::GetInstance()->model();
222 model_->AddObserver(this);
224 registrar_.Add(this, content::NOTIFICATION_RENDER_WIDGET_HOST_HANG,
225 content::NotificationService::AllSources());
226 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
227 content::NotificationService::AllSources());
228 #endif // defined(ENABLE_TASK_MANAGER)
231 ProcessesEventRouter::~ProcessesEventRouter() {
232 #if defined(ENABLE_TASK_MANAGER)
233 registrar_.Remove(this, content::NOTIFICATION_RENDER_WIDGET_HOST_HANG,
234 content::NotificationService::AllSources());
235 registrar_.Remove(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
236 content::NotificationService::AllSources());
238 if (task_manager_listening_)
239 model_->StopListening();
241 model_->RemoveObserver(this);
242 #endif // defined(ENABLE_TASK_MANAGER)
245 void ProcessesEventRouter::ListenerAdded() {
246 #if defined(ENABLE_TASK_MANAGER)
247 // The task manager has its own ref count to balance other callers of
248 // StartUpdating/StopUpdating.
249 model_->StartUpdating();
250 #endif // defined(ENABLE_TASK_MANAGER)
251 ++listeners_;
254 void ProcessesEventRouter::ListenerRemoved() {
255 DCHECK_GT(listeners_, 0);
256 --listeners_;
257 #if defined(ENABLE_TASK_MANAGER)
258 // The task manager has its own ref count to balance other callers of
259 // StartUpdating/StopUpdating.
260 model_->StopUpdating();
261 #endif // defined(ENABLE_TASK_MANAGER)
264 void ProcessesEventRouter::StartTaskManagerListening() {
265 #if defined(ENABLE_TASK_MANAGER)
266 if (!task_manager_listening_) {
267 model_->StartListening();
268 task_manager_listening_ = true;
270 #endif // defined(ENABLE_TASK_MANAGER)
273 void ProcessesEventRouter::Observe(
274 int type,
275 const content::NotificationSource& source,
276 const content::NotificationDetails& details) {
278 switch (type) {
279 case content::NOTIFICATION_RENDER_WIDGET_HOST_HANG:
280 ProcessHangEvent(
281 content::Source<content::RenderWidgetHost>(source).ptr());
282 break;
283 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED:
284 ProcessClosedEvent(
285 content::Source<content::RenderProcessHost>(source).ptr(),
286 content::Details<content::RenderProcessHost::RendererClosedDetails>(
287 details).ptr());
288 break;
289 default:
290 NOTREACHED() << "Unexpected observe of type " << type;
292 return;
295 void ProcessesEventRouter::OnItemsAdded(int start, int length) {
296 #if defined(ENABLE_TASK_MANAGER)
297 DCHECK_EQ(length, 1);
298 int index = start;
300 std::string event(keys::kOnCreated);
301 if (!HasEventListeners(event))
302 return;
304 // If the item being added is not the first one in the group, find the base
305 // index and use it for retrieving the process data.
306 if (!model_->IsResourceFirstInGroup(start)) {
307 index = model_->GetGroupIndexForResource(start);
310 scoped_ptr<base::ListValue> args(new base::ListValue());
311 base::DictionaryValue* process = CreateProcessFromModel(
312 model_->GetUniqueChildProcessId(index), model_, index, false);
313 DCHECK(process != NULL);
315 if (process == NULL)
316 return;
318 args->Append(process);
320 DispatchEvent(keys::kOnCreated, args.Pass());
321 #endif // defined(ENABLE_TASK_MANAGER)
324 void ProcessesEventRouter::OnItemsChanged(int start, int length) {
325 #if defined(ENABLE_TASK_MANAGER)
326 // If we don't have any listeners, return immediately.
327 if (listeners_ == 0)
328 return;
330 if (!model_)
331 return;
333 // We need to know which type of onUpdated events to fire and whether to
334 // collect memory or not.
335 std::string updated_event(keys::kOnUpdated);
336 std::string updated_event_memory(keys::kOnUpdatedWithMemory);
337 bool updated = HasEventListeners(updated_event);
338 bool updated_memory = HasEventListeners(updated_event_memory);
340 DCHECK(updated || updated_memory);
342 IDMap<base::DictionaryValue> processes_map;
343 for (int i = start; i < start + length; i++) {
344 if (model_->IsResourceFirstInGroup(i)) {
345 int id = model_->GetUniqueChildProcessId(i);
346 base::DictionaryValue* process = CreateProcessFromModel(id, model_, i,
347 true);
348 processes_map.AddWithID(process, i);
352 int id;
353 std::string idkey(keys::kIdKey);
354 base::DictionaryValue* processes = new base::DictionaryValue();
356 if (updated) {
357 IDMap<base::DictionaryValue>::iterator it(&processes_map);
358 for (; !it.IsAtEnd(); it.Advance()) {
359 if (!it.GetCurrentValue()->GetInteger(idkey, &id))
360 continue;
362 // Store each process indexed by the string version of its id.
363 processes->Set(base::IntToString(id), it.GetCurrentValue());
366 scoped_ptr<base::ListValue> args(new base::ListValue());
367 args->Append(processes);
368 DispatchEvent(keys::kOnUpdated, args.Pass());
371 if (updated_memory) {
372 IDMap<base::DictionaryValue>::iterator it(&processes_map);
373 for (; !it.IsAtEnd(); it.Advance()) {
374 if (!it.GetCurrentValue()->GetInteger(idkey, &id))
375 continue;
377 AddMemoryDetails(it.GetCurrentValue(), model_, it.GetCurrentKey());
379 // Store each process indexed by the string version of its id if we didn't
380 // already insert it as part of the onUpdated processing above.
381 if (!updated)
382 processes->Set(base::IntToString(id), it.GetCurrentValue());
385 scoped_ptr<base::ListValue> args(new base::ListValue());
386 args->Append(processes);
387 DispatchEvent(keys::kOnUpdatedWithMemory, args.Pass());
389 #endif // defined(ENABLE_TASK_MANAGER)
392 void ProcessesEventRouter::OnItemsToBeRemoved(int start, int length) {
393 #if defined(ENABLE_TASK_MANAGER)
394 DCHECK_EQ(length, 1);
396 // Process exit for renderer processes has the data about exit code and
397 // termination status, therefore we will rely on notifications and not on
398 // the Task Manager data. We do use the rest of this method for non-renderer
399 // processes.
400 if (model_->GetResourceType(start) == task_manager::Resource::RENDERER)
401 return;
403 // The callback function parameters.
404 scoped_ptr<base::ListValue> args(new base::ListValue());
406 // First arg: The id of the process that was closed.
407 args->Append(new base::FundamentalValue(
408 model_->GetUniqueChildProcessId(start)));
410 // Second arg: The exit type for the process.
411 args->Append(new base::FundamentalValue(0));
413 // Third arg: The exit code for the process.
414 args->Append(new base::FundamentalValue(0));
416 DispatchEvent(keys::kOnExited, args.Pass());
417 #endif // defined(ENABLE_TASK_MANAGER)
420 void ProcessesEventRouter::ProcessHangEvent(content::RenderWidgetHost* widget) {
421 #if defined(ENABLE_TASK_MANAGER)
422 std::string event(keys::kOnUnresponsive);
423 if (!HasEventListeners(event))
424 return;
426 base::DictionaryValue* process = NULL;
427 int count = model_->ResourceCount();
428 int id = widget->GetProcess()->GetID();
430 for (int i = 0; i < count; ++i) {
431 if (model_->IsResourceFirstInGroup(i)) {
432 if (id == model_->GetUniqueChildProcessId(i)) {
433 process = CreateProcessFromModel(id, model_, i, false);
434 break;
439 if (process == NULL)
440 return;
442 scoped_ptr<base::ListValue> args(new base::ListValue());
443 args->Append(process);
445 DispatchEvent(keys::kOnUnresponsive, args.Pass());
446 #endif // defined(ENABLE_TASK_MANAGER)
449 void ProcessesEventRouter::ProcessClosedEvent(
450 content::RenderProcessHost* rph,
451 content::RenderProcessHost::RendererClosedDetails* details) {
452 #if defined(ENABLE_TASK_MANAGER)
453 // The callback function parameters.
454 scoped_ptr<base::ListValue> args(new base::ListValue());
456 // First arg: The id of the process that was closed.
457 args->Append(new base::FundamentalValue(rph->GetID()));
459 // Second arg: The exit type for the process.
460 args->Append(new base::FundamentalValue(details->status));
462 // Third arg: The exit code for the process.
463 args->Append(new base::FundamentalValue(details->exit_code));
465 DispatchEvent(keys::kOnExited, args.Pass());
466 #endif // defined(ENABLE_TASK_MANAGER)
469 void ProcessesEventRouter::DispatchEvent(
470 const std::string& event_name,
471 scoped_ptr<base::ListValue> event_args) {
472 EventRouter* event_router = EventRouter::Get(browser_context_);
473 if (event_router) {
474 scoped_ptr<extensions::Event> event(new extensions::Event(
475 event_name, event_args.Pass()));
476 event_router->BroadcastEvent(event.Pass());
480 bool ProcessesEventRouter::HasEventListeners(const std::string& event_name) {
481 EventRouter* event_router = EventRouter::Get(browser_context_);
482 return event_router && event_router->HasEventListener(event_name);
485 ProcessesAPI::ProcessesAPI(content::BrowserContext* context)
486 : browser_context_(context) {
487 EventRouter* event_router = EventRouter::Get(browser_context_);
488 event_router->RegisterObserver(this, processes_api_constants::kOnUpdated);
489 event_router->RegisterObserver(this,
490 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>();
498 ProcessesAPI::~ProcessesAPI() {
501 void ProcessesAPI::Shutdown() {
502 EventRouter::Get(browser_context_)->UnregisterObserver(this);
505 static base::LazyInstance<BrowserContextKeyedAPIFactory<ProcessesAPI> >
506 g_factory = LAZY_INSTANCE_INITIALIZER;
508 // static
509 BrowserContextKeyedAPIFactory<ProcessesAPI>*
510 ProcessesAPI::GetFactoryInstance() {
511 return g_factory.Pointer();
514 // static
515 ProcessesAPI* ProcessesAPI::Get(content::BrowserContext* context) {
516 return BrowserContextKeyedAPIFactory<ProcessesAPI>::Get(context);
519 ProcessesEventRouter* ProcessesAPI::processes_event_router() {
520 if (!processes_event_router_)
521 processes_event_router_.reset(new ProcessesEventRouter(browser_context_));
522 return processes_event_router_.get();
525 void ProcessesAPI::OnListenerAdded(const EventListenerInfo& details) {
526 // We lazily tell the TaskManager to start updating when listeners to the
527 // processes.onUpdated or processes.onUpdatedWithMemory events arrive.
528 processes_event_router()->ListenerAdded();
531 void ProcessesAPI::OnListenerRemoved(const EventListenerInfo& details) {
532 // If a processes.onUpdated or processes.onUpdatedWithMemory event listener
533 // is removed (or a process with one exits), then we let the extension API
534 // know that it has one fewer listener.
535 processes_event_router()->ListenerRemoved();
538 GetProcessIdForTabFunction::GetProcessIdForTabFunction() : tab_id_(-1) {
541 bool GetProcessIdForTabFunction::RunImpl() {
542 #if defined(ENABLE_TASK_MANAGER)
543 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &tab_id_));
545 // Add a reference, which is balanced in GetProcessIdForTab to keep the object
546 // around and allow for the callback to be invoked.
547 AddRef();
549 // If the task manager is already listening, just post a task to execute
550 // which will invoke the callback once we have returned from this function.
551 // Otherwise, wait for the notification that the task manager is done with
552 // the data gathering.
553 if (ProcessesAPI::Get(GetProfile())
554 ->processes_event_router()
555 ->is_task_manager_listening()) {
556 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
557 &GetProcessIdForTabFunction::GetProcessIdForTab, this));
558 } else {
559 TaskManager::GetInstance()->model()->RegisterOnDataReadyCallback(
560 base::Bind(&GetProcessIdForTabFunction::GetProcessIdForTab, this));
562 ProcessesAPI::Get(GetProfile())
563 ->processes_event_router()
564 ->StartTaskManagerListening();
567 return true;
568 #else
569 error_ = errors::kExtensionNotSupported;
570 return false;
571 #endif // defined(ENABLE_TASK_MANAGER)
574 void GetProcessIdForTabFunction::GetProcessIdForTab() {
575 content::WebContents* contents = NULL;
576 int tab_index = -1;
577 if (!ExtensionTabUtil::GetTabById(tab_id_,
578 GetProfile(),
579 include_incognito(),
580 NULL,
581 NULL,
582 &contents,
583 &tab_index)) {
584 error_ = ErrorUtils::FormatErrorMessage(
585 extensions::tabs_constants::kTabNotFoundError,
586 base::IntToString(tab_id_));
587 SetResult(new base::FundamentalValue(-1));
588 SendResponse(false);
589 } else {
590 int process_id = contents->GetRenderProcessHost()->GetID();
591 SetResult(new base::FundamentalValue(process_id));
592 SendResponse(true);
595 // Balance the AddRef in the RunImpl.
596 Release();
599 TerminateFunction::TerminateFunction() : process_id_(-1) {
602 bool TerminateFunction::RunImpl() {
603 #if defined(ENABLE_TASK_MANAGER)
604 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &process_id_));
606 // Add a reference, which is balanced in TerminateProcess to keep the object
607 // around and allow for the callback to be invoked.
608 AddRef();
610 // If the task manager is already listening, just post a task to execute
611 // which will invoke the callback once we have returned from this function.
612 // Otherwise, wait for the notification that the task manager is done with
613 // the data gathering.
614 if (ProcessesAPI::Get(GetProfile())
615 ->processes_event_router()
616 ->is_task_manager_listening()) {
617 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
618 &TerminateFunction::TerminateProcess, this));
619 } else {
620 TaskManager::GetInstance()->model()->RegisterOnDataReadyCallback(
621 base::Bind(&TerminateFunction::TerminateProcess, this));
623 ProcessesAPI::Get(GetProfile())
624 ->processes_event_router()
625 ->StartTaskManagerListening();
628 return true;
629 #else
630 error_ = errors::kExtensionNotSupported;
631 return false;
632 #endif // defined(ENABLE_TASK_MANAGER)
636 void TerminateFunction::TerminateProcess() {
637 #if defined(ENABLE_TASK_MANAGER)
638 TaskManagerModel* model = TaskManager::GetInstance()->model();
640 int count = model->ResourceCount();
641 bool killed = false;
642 bool found = false;
644 for (int i = 0; i < count; ++i) {
645 if (model->IsResourceFirstInGroup(i)) {
646 if (process_id_ == model->GetUniqueChildProcessId(i)) {
647 found = true;
648 killed = base::KillProcess(model->GetProcess(i),
649 content::RESULT_CODE_KILLED, true);
650 UMA_HISTOGRAM_COUNTS("ChildProcess.KilledByExtensionAPI", 1);
651 break;
656 if (!found) {
657 error_ = ErrorUtils::FormatErrorMessage(errors::kProcessNotFound,
658 base::IntToString(process_id_));
659 SendResponse(false);
660 } else {
661 SetResult(new base::FundamentalValue(killed));
662 SendResponse(true);
665 // Balance the AddRef in the RunImpl.
666 Release();
667 #else
668 error_ = errors::kExtensionNotSupported;
669 SendResponse(false);
670 #endif // defined(ENABLE_TASK_MANAGER)
673 GetProcessInfoFunction::GetProcessInfoFunction()
674 #if defined(ENABLE_TASK_MANAGER)
675 : memory_(false)
676 #endif
680 GetProcessInfoFunction::~GetProcessInfoFunction() {
683 bool GetProcessInfoFunction::RunImpl() {
684 #if defined(ENABLE_TASK_MANAGER)
685 base::Value* processes = NULL;
687 EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &processes));
688 EXTENSION_FUNCTION_VALIDATE(args_->GetBoolean(1, &memory_));
690 EXTENSION_FUNCTION_VALIDATE(extensions::ReadOneOrMoreIntegers(
691 processes, &process_ids_));
693 // Add a reference, which is balanced in GatherProcessInfo to keep the object
694 // around and allow for the callback to be invoked.
695 AddRef();
697 // If the task manager is already listening, just post a task to execute
698 // which will invoke the callback once we have returned from this function.
699 // Otherwise, wait for the notification that the task manager is done with
700 // the data gathering.
701 if (ProcessesAPI::Get(GetProfile())
702 ->processes_event_router()
703 ->is_task_manager_listening()) {
704 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
705 &GetProcessInfoFunction::GatherProcessInfo, this));
706 } else {
707 TaskManager::GetInstance()->model()->RegisterOnDataReadyCallback(
708 base::Bind(&GetProcessInfoFunction::GatherProcessInfo, this));
710 ProcessesAPI::Get(GetProfile())
711 ->processes_event_router()
712 ->StartTaskManagerListening();
714 return true;
716 #else
717 error_ = errors::kExtensionNotSupported;
718 return false;
719 #endif // defined(ENABLE_TASK_MANAGER)
722 void GetProcessInfoFunction::GatherProcessInfo() {
723 #if defined(ENABLE_TASK_MANAGER)
724 TaskManagerModel* model = TaskManager::GetInstance()->model();
725 base::DictionaryValue* processes = new base::DictionaryValue();
727 // If there are no process IDs specified, it means we need to return all of
728 // the ones we know of.
729 if (process_ids_.size() == 0) {
730 int resources = model->ResourceCount();
731 for (int i = 0; i < resources; ++i) {
732 if (model->IsResourceFirstInGroup(i)) {
733 int id = model->GetUniqueChildProcessId(i);
734 base::DictionaryValue* d = CreateProcessFromModel(id, model, i, false);
735 if (memory_)
736 AddMemoryDetails(d, model, i);
737 processes->Set(base::IntToString(id), d);
740 } else {
741 int resources = model->ResourceCount();
742 for (int i = 0; i < resources; ++i) {
743 if (model->IsResourceFirstInGroup(i)) {
744 int id = model->GetUniqueChildProcessId(i);
745 std::vector<int>::iterator proc_id = std::find(process_ids_.begin(),
746 process_ids_.end(), id);
747 if (proc_id != process_ids_.end()) {
748 base::DictionaryValue* d =
749 CreateProcessFromModel(id, model, i, false);
750 if (memory_)
751 AddMemoryDetails(d, model, i);
752 processes->Set(base::IntToString(id), d);
754 process_ids_.erase(proc_id);
755 if (process_ids_.size() == 0)
756 break;
760 DCHECK_EQ(process_ids_.size(), 0U);
763 SetResult(processes);
764 SendResponse(true);
766 // Balance the AddRef in the RunImpl.
767 Release();
768 #endif // defined(ENABLE_TASK_MANAGER)
771 } // namespace extensions