Elim cr-checkbox
[chromium-blink-merge.git] / chrome / browser / extensions / api / processes / processes_api.cc
blob2c1b7aad299bdb1899ea559bb305e0feb4dfe93e
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/location.h"
11 #include "base/metrics/histogram.h"
12 #include "base/single_thread_task_runner.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/thread_task_runner_handle.h"
16 #include "base/values.h"
17 #include "chrome/browser/chrome_notification_types.h"
18 #include "chrome/browser/extensions/api/processes/processes_api_constants.h"
19 #include "chrome/browser/extensions/api/tabs/tabs_constants.h"
20 #include "chrome/browser/extensions/extension_service.h"
21 #include "chrome/browser/extensions/extension_tab_util.h"
22 #include "chrome/browser/profiles/profile.h"
23 #include "chrome/browser/task_manager/resource_provider.h"
24 #include "chrome/browser/task_manager/task_manager.h"
25 #include "content/public/browser/browser_context.h"
26 #include "content/public/browser/notification_details.h"
27 #include "content/public/browser/notification_service.h"
28 #include "content/public/browser/notification_source.h"
29 #include "content/public/browser/notification_types.h"
30 #include "content/public/browser/render_process_host.h"
31 #include "content/public/browser/render_view_host.h"
32 #include "content/public/browser/render_widget_host.h"
33 #include "content/public/browser/render_widget_host_iterator.h"
34 #include "content/public/browser/web_contents.h"
35 #include "content/public/common/result_codes.h"
36 #include "extensions/browser/event_router.h"
37 #include "extensions/browser/extension_function_registry.h"
38 #include "extensions/browser/extension_function_util.h"
39 #include "extensions/common/error_utils.h"
41 namespace extensions {
43 namespace keys = processes_api_constants;
44 namespace errors = processes_api_constants;
46 namespace {
48 #if defined(ENABLE_TASK_MANAGER)
50 base::DictionaryValue* CreateCacheData(
51 const blink::WebCache::ResourceTypeStat& stat) {
53 base::DictionaryValue* cache = new base::DictionaryValue();
54 cache->SetDouble(keys::kCacheSize, static_cast<double>(stat.size));
55 cache->SetDouble(keys::kCacheLiveSize, static_cast<double>(stat.liveSize));
56 return cache;
59 void SetProcessType(base::DictionaryValue* result,
60 TaskManagerModel* model,
61 int index) {
62 // Determine process type.
63 std::string type = keys::kProcessTypeOther;
64 task_manager::Resource::Type resource_type = model->GetResourceType(index);
65 switch (resource_type) {
66 case task_manager::Resource::BROWSER:
67 type = keys::kProcessTypeBrowser;
68 break;
69 case task_manager::Resource::RENDERER:
70 type = keys::kProcessTypeRenderer;
71 break;
72 case task_manager::Resource::EXTENSION:
73 type = keys::kProcessTypeExtension;
74 break;
75 case task_manager::Resource::NOTIFICATION:
76 type = keys::kProcessTypeNotification;
77 break;
78 case task_manager::Resource::PLUGIN:
79 type = keys::kProcessTypePlugin;
80 break;
81 case task_manager::Resource::WORKER:
82 type = keys::kProcessTypeWorker;
83 break;
84 case task_manager::Resource::NACL:
85 type = keys::kProcessTypeNacl;
86 break;
87 case task_manager::Resource::UTILITY:
88 type = keys::kProcessTypeUtility;
89 break;
90 case task_manager::Resource::GPU:
91 type = keys::kProcessTypeGPU;
92 break;
93 case task_manager::Resource::ZYGOTE:
94 case task_manager::Resource::SANDBOX_HELPER:
95 case task_manager::Resource::UNKNOWN:
96 type = keys::kProcessTypeOther;
97 break;
98 default:
99 NOTREACHED() << "Unknown resource type.";
101 result->SetString(keys::kTypeKey, type);
104 base::ListValue* GetTabsForProcess(int process_id) {
105 base::ListValue* tabs_list = new base::ListValue();
107 // The tabs list only makes sense for render processes, so if we don't find
108 // one, just return the empty list.
109 content::RenderProcessHost* rph =
110 content::RenderProcessHost::FromID(process_id);
111 if (rph == NULL)
112 return tabs_list;
114 int tab_id = -1;
115 // We need to loop through all the RVHs to ensure we collect the set of all
116 // tabs using this renderer process.
117 scoped_ptr<content::RenderWidgetHostIterator> widgets(
118 content::RenderWidgetHost::GetRenderWidgetHosts());
119 while (content::RenderWidgetHost* widget = widgets->GetNextHost()) {
120 if (widget->GetProcess()->GetID() != process_id)
121 continue;
122 if (!widget->IsRenderView())
123 continue;
125 content::RenderViewHost* host = content::RenderViewHost::From(widget);
126 content::WebContents* contents =
127 content::WebContents::FromRenderViewHost(host);
128 if (contents) {
129 tab_id = ExtensionTabUtil::GetTabId(contents);
130 if (tab_id != -1)
131 tabs_list->Append(new base::FundamentalValue(tab_id));
135 return tabs_list;
138 // This function creates a Process object to be returned to the extensions
139 // using these APIs. For memory details, which are not added by this function,
140 // the callers need to use AddMemoryDetails.
141 base::DictionaryValue* CreateProcessFromModel(int process_id,
142 TaskManagerModel* model,
143 int index,
144 bool include_optional) {
145 base::DictionaryValue* result = new base::DictionaryValue();
146 size_t mem;
148 result->SetInteger(keys::kIdKey, process_id);
149 result->SetInteger(keys::kOsProcessIdKey, model->GetProcessId(index));
150 SetProcessType(result, model, index);
151 result->SetString(keys::kTitleKey, model->GetResourceTitle(index));
152 result->SetString(keys::kProfileKey,
153 model->GetResourceProfileName(index));
154 result->SetInteger(keys::kNaClDebugPortKey,
155 model->GetNaClDebugStubPort(index));
157 result->Set(keys::kTabsListKey, GetTabsForProcess(process_id));
159 // If we don't need to include the optional properties, just return now.
160 if (!include_optional)
161 return result;
163 result->SetDouble(keys::kCpuKey, model->GetCPUUsage(index));
165 if (model->GetV8Memory(index, &mem))
166 result->SetDouble(keys::kJsMemoryAllocatedKey,
167 static_cast<double>(mem));
169 if (model->GetV8MemoryUsed(index, &mem))
170 result->SetDouble(keys::kJsMemoryUsedKey,
171 static_cast<double>(mem));
173 if (model->GetSqliteMemoryUsedBytes(index, &mem))
174 result->SetDouble(keys::kSqliteMemoryKey,
175 static_cast<double>(mem));
177 blink::WebCache::ResourceTypeStats cache_stats;
178 if (model->GetWebCoreCacheStats(index, &cache_stats)) {
179 result->Set(keys::kImageCacheKey,
180 CreateCacheData(cache_stats.images));
181 result->Set(keys::kScriptCacheKey,
182 CreateCacheData(cache_stats.scripts));
183 result->Set(keys::kCssCacheKey,
184 CreateCacheData(cache_stats.cssStyleSheets));
187 // Network is reported by the TaskManager per resource (tab), not per
188 // process, therefore we need to iterate through the group of resources
189 // and aggregate the data.
190 int64 net = 0;
191 int length = model->GetGroupRangeForResource(index).second;
192 for (int i = 0; i < length; ++i)
193 net += model->GetNetworkUsage(index + i);
194 result->SetDouble(keys::kNetworkKey, static_cast<double>(net));
196 return result;
199 // Since memory details are expensive to gather, we don't do it by default.
200 // This function is a helper to add memory details data to an existing
201 // Process object representation.
202 void AddMemoryDetails(base::DictionaryValue* result,
203 TaskManagerModel* model,
204 int index) {
205 size_t mem;
206 int64 pr_mem = model->GetPrivateMemory(index, &mem) ?
207 static_cast<int64>(mem) : -1;
208 result->SetDouble(keys::kPrivateMemoryKey, static_cast<double>(pr_mem));
211 #endif // defined(ENABLE_TASK_MANAGER)
213 } // namespace
215 ProcessesEventRouter::ProcessesEventRouter(content::BrowserContext* context)
216 : browser_context_(context), listeners_(0), task_manager_listening_(false) {
217 #if defined(ENABLE_TASK_MANAGER)
218 model_ = TaskManager::GetInstance()->model();
219 model_->AddObserver(this);
221 registrar_.Add(this, content::NOTIFICATION_RENDER_WIDGET_HOST_HANG,
222 content::NotificationService::AllSources());
223 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
224 content::NotificationService::AllSources());
225 #endif // defined(ENABLE_TASK_MANAGER)
228 ProcessesEventRouter::~ProcessesEventRouter() {
229 #if defined(ENABLE_TASK_MANAGER)
230 registrar_.Remove(this, content::NOTIFICATION_RENDER_WIDGET_HOST_HANG,
231 content::NotificationService::AllSources());
232 registrar_.Remove(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
233 content::NotificationService::AllSources());
235 if (task_manager_listening_)
236 model_->StopListening();
238 model_->RemoveObserver(this);
239 #endif // defined(ENABLE_TASK_MANAGER)
242 void ProcessesEventRouter::ListenerAdded() {
243 #if defined(ENABLE_TASK_MANAGER)
244 // The task manager has its own ref count to balance other callers of
245 // StartUpdating/StopUpdating.
246 model_->StartUpdating();
247 #endif // defined(ENABLE_TASK_MANAGER)
248 ++listeners_;
251 void ProcessesEventRouter::ListenerRemoved() {
252 DCHECK_GT(listeners_, 0);
253 --listeners_;
254 #if defined(ENABLE_TASK_MANAGER)
255 // The task manager has its own ref count to balance other callers of
256 // StartUpdating/StopUpdating.
257 model_->StopUpdating();
258 #endif // defined(ENABLE_TASK_MANAGER)
261 void ProcessesEventRouter::StartTaskManagerListening() {
262 #if defined(ENABLE_TASK_MANAGER)
263 if (!task_manager_listening_) {
264 model_->StartListening();
265 task_manager_listening_ = true;
267 #endif // defined(ENABLE_TASK_MANAGER)
270 void ProcessesEventRouter::Observe(
271 int type,
272 const content::NotificationSource& source,
273 const content::NotificationDetails& details) {
275 switch (type) {
276 case content::NOTIFICATION_RENDER_WIDGET_HOST_HANG:
277 ProcessHangEvent(
278 content::Source<content::RenderWidgetHost>(source).ptr());
279 break;
280 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED:
281 ProcessClosedEvent(
282 content::Source<content::RenderProcessHost>(source).ptr(),
283 content::Details<content::RenderProcessHost::RendererClosedDetails>(
284 details).ptr());
285 break;
286 default:
287 NOTREACHED() << "Unexpected observe of type " << type;
289 return;
292 void ProcessesEventRouter::OnItemsAdded(int start, int length) {
293 #if defined(ENABLE_TASK_MANAGER)
294 DCHECK_EQ(length, 1);
295 int index = start;
297 std::string event(keys::kOnCreated);
298 if (!HasEventListeners(event))
299 return;
301 // If the item being added is not the first one in the group, find the base
302 // index and use it for retrieving the process data.
303 if (!model_->IsResourceFirstInGroup(start)) {
304 index = model_->GetGroupIndexForResource(start);
307 scoped_ptr<base::ListValue> args(new base::ListValue());
308 base::DictionaryValue* process = CreateProcessFromModel(
309 model_->GetUniqueChildProcessId(index), model_, index, false);
310 DCHECK(process != NULL);
312 if (process == NULL)
313 return;
315 args->Append(process);
317 DispatchEvent(events::PROCESSES_ON_CREATED, keys::kOnCreated, args.Pass());
318 #endif // defined(ENABLE_TASK_MANAGER)
321 void ProcessesEventRouter::OnItemsChanged(int start, int length) {
322 #if defined(ENABLE_TASK_MANAGER)
323 // If we don't have any listeners, return immediately.
324 if (listeners_ == 0)
325 return;
327 if (!model_)
328 return;
330 // We need to know which type of onUpdated events to fire and whether to
331 // collect memory or not.
332 std::string updated_event(keys::kOnUpdated);
333 std::string updated_event_memory(keys::kOnUpdatedWithMemory);
334 bool updated = HasEventListeners(updated_event);
335 bool updated_memory = HasEventListeners(updated_event_memory);
337 DCHECK(updated || updated_memory);
339 IDMap<base::DictionaryValue> processes_map;
340 for (int i = start; i < start + length; i++) {
341 if (model_->IsResourceFirstInGroup(i)) {
342 int id = model_->GetUniqueChildProcessId(i);
343 base::DictionaryValue* process = CreateProcessFromModel(id, model_, i,
344 true);
345 processes_map.AddWithID(process, i);
349 int id;
350 std::string idkey(keys::kIdKey);
351 base::DictionaryValue* processes = new base::DictionaryValue();
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;
359 // Store each process indexed by the string version of its id.
360 processes->Set(base::IntToString(id), it.GetCurrentValue());
363 scoped_ptr<base::ListValue> args(new base::ListValue());
364 args->Append(processes);
365 DispatchEvent(events::PROCESSES_ON_UPDATED, keys::kOnUpdated, args.Pass());
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;
374 AddMemoryDetails(it.GetCurrentValue(), model_, it.GetCurrentKey());
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());
382 scoped_ptr<base::ListValue> args(new base::ListValue());
383 args->Append(processes);
384 DispatchEvent(events::PROCESSES_ON_UPDATED_WITH_MEMORY,
385 keys::kOnUpdatedWithMemory, args.Pass());
387 #endif // defined(ENABLE_TASK_MANAGER)
390 void ProcessesEventRouter::OnItemsToBeRemoved(int start, int length) {
391 #if defined(ENABLE_TASK_MANAGER)
392 DCHECK_EQ(length, 1);
394 // Process exit for renderer processes has the data about exit code and
395 // termination status, therefore we will rely on notifications and not on
396 // the Task Manager data. We do use the rest of this method for non-renderer
397 // processes.
398 if (model_->GetResourceType(start) == task_manager::Resource::RENDERER)
399 return;
401 // The callback function parameters.
402 scoped_ptr<base::ListValue> args(new base::ListValue());
404 // First arg: The id of the process that was closed.
405 args->Append(new base::FundamentalValue(
406 model_->GetUniqueChildProcessId(start)));
408 // Second arg: The exit type for the process.
409 args->Append(new base::FundamentalValue(0));
411 // Third arg: The exit code for the process.
412 args->Append(new base::FundamentalValue(0));
414 DispatchEvent(events::PROCESSES_ON_EXITED, keys::kOnExited, args.Pass());
415 #endif // defined(ENABLE_TASK_MANAGER)
418 void ProcessesEventRouter::ProcessHangEvent(content::RenderWidgetHost* widget) {
419 #if defined(ENABLE_TASK_MANAGER)
420 std::string event(keys::kOnUnresponsive);
421 if (!HasEventListeners(event))
422 return;
424 base::DictionaryValue* process = NULL;
425 int count = model_->ResourceCount();
426 int id = widget->GetProcess()->GetID();
428 for (int i = 0; i < count; ++i) {
429 if (model_->IsResourceFirstInGroup(i)) {
430 if (id == model_->GetUniqueChildProcessId(i)) {
431 process = CreateProcessFromModel(id, model_, i, false);
432 break;
437 if (process == NULL)
438 return;
440 scoped_ptr<base::ListValue> args(new base::ListValue());
441 args->Append(process);
443 DispatchEvent(events::PROCESSES_ON_UNRESPONSIVE, keys::kOnUnresponsive,
444 args.Pass());
445 #endif // defined(ENABLE_TASK_MANAGER)
448 void ProcessesEventRouter::ProcessClosedEvent(
449 content::RenderProcessHost* rph,
450 content::RenderProcessHost::RendererClosedDetails* details) {
451 #if defined(ENABLE_TASK_MANAGER)
452 // The callback function parameters.
453 scoped_ptr<base::ListValue> args(new base::ListValue());
455 // First arg: The id of the process that was closed.
456 args->Append(new base::FundamentalValue(rph->GetID()));
458 // Second arg: The exit type for the process.
459 args->Append(new base::FundamentalValue(details->status));
461 // Third arg: The exit code for the process.
462 args->Append(new base::FundamentalValue(details->exit_code));
464 DispatchEvent(events::PROCESSES_ON_EXITED, keys::kOnExited, args.Pass());
465 #endif // defined(ENABLE_TASK_MANAGER)
468 void ProcessesEventRouter::DispatchEvent(
469 events::HistogramValue histogram_value,
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<Event> event(
475 new Event(histogram_value, 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<GetProcessIdForTabFunction>();
494 registry->RegisterFunction<TerminateFunction>();
495 registry->RegisterFunction<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::RunAsync() {
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::ThreadTaskRunnerHandle::Get()->PostTask(
557 FROM_HERE,
558 base::Bind(&GetProcessIdForTabFunction::GetProcessIdForTab, this));
559 } else {
560 TaskManager::GetInstance()->model()->RegisterOnDataReadyCallback(
561 base::Bind(&GetProcessIdForTabFunction::GetProcessIdForTab, this));
563 ProcessesAPI::Get(GetProfile())
564 ->processes_event_router()
565 ->StartTaskManagerListening();
568 return true;
569 #else
570 error_ = errors::kExtensionNotSupported;
571 return false;
572 #endif // defined(ENABLE_TASK_MANAGER)
575 void GetProcessIdForTabFunction::GetProcessIdForTab() {
576 content::WebContents* contents = NULL;
577 int tab_index = -1;
578 if (!ExtensionTabUtil::GetTabById(tab_id_,
579 GetProfile(),
580 include_incognito(),
581 NULL,
582 NULL,
583 &contents,
584 &tab_index)) {
585 error_ = ErrorUtils::FormatErrorMessage(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 RunAsync.
596 Release();
599 TerminateFunction::TerminateFunction() : process_id_(-1) {
602 bool TerminateFunction::RunAsync() {
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::ThreadTaskRunnerHandle::Get()->PostTask(
618 FROM_HERE, base::Bind(&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 base::Process process =
649 base::Process::DeprecatedGetProcessFromHandle(model->GetProcess(i));
650 killed = process.Terminate(content::RESULT_CODE_KILLED, true);
651 UMA_HISTOGRAM_COUNTS("ChildProcess.KilledByExtensionAPI", 1);
652 break;
657 if (!found) {
658 error_ = ErrorUtils::FormatErrorMessage(errors::kProcessNotFound,
659 base::IntToString(process_id_));
660 SendResponse(false);
661 } else {
662 SetResult(new base::FundamentalValue(killed));
663 SendResponse(true);
666 // Balance the AddRef in the RunAsync.
667 Release();
668 #else
669 error_ = errors::kExtensionNotSupported;
670 SendResponse(false);
671 #endif // defined(ENABLE_TASK_MANAGER)
674 GetProcessInfoFunction::GetProcessInfoFunction()
675 #if defined(ENABLE_TASK_MANAGER)
676 : memory_(false)
677 #endif
681 GetProcessInfoFunction::~GetProcessInfoFunction() {
684 bool GetProcessInfoFunction::RunAsync() {
685 #if defined(ENABLE_TASK_MANAGER)
686 base::Value* processes = NULL;
688 EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &processes));
689 EXTENSION_FUNCTION_VALIDATE(args_->GetBoolean(1, &memory_));
690 EXTENSION_FUNCTION_VALIDATE(ReadOneOrMoreIntegers(processes, &process_ids_));
692 // Add a reference, which is balanced in GatherProcessInfo to keep the object
693 // around and allow for the callback to be invoked.
694 AddRef();
696 // If the task manager is already listening, just post a task to execute
697 // which will invoke the callback once we have returned from this function.
698 // Otherwise, wait for the notification that the task manager is done with
699 // the data gathering.
700 if (ProcessesAPI::Get(GetProfile())
701 ->processes_event_router()
702 ->is_task_manager_listening()) {
703 base::ThreadTaskRunnerHandle::Get()->PostTask(
704 FROM_HERE,
705 base::Bind(&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 RunAsync.
767 Release();
768 #endif // defined(ENABLE_TASK_MANAGER)
771 } // namespace extensions