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
;
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
));
57 void SetProcessType(base::DictionaryValue
* result
,
58 TaskManagerModel
* model
,
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
;
67 case task_manager::Resource::RENDERER
:
68 type
= keys::kProcessTypeRenderer
;
70 case task_manager::Resource::EXTENSION
:
71 type
= keys::kProcessTypeExtension
;
73 case task_manager::Resource::NOTIFICATION
:
74 type
= keys::kProcessTypeNotification
;
76 case task_manager::Resource::PLUGIN
:
77 type
= keys::kProcessTypePlugin
;
79 case task_manager::Resource::WORKER
:
80 type
= keys::kProcessTypeWorker
;
82 case task_manager::Resource::NACL
:
83 type
= keys::kProcessTypeNacl
;
85 case task_manager::Resource::UTILITY
:
86 type
= keys::kProcessTypeUtility
;
88 case task_manager::Resource::GPU
:
89 type
= keys::kProcessTypeGPU
;
91 case task_manager::Resource::ZYGOTE
:
92 case task_manager::Resource::SANDBOX_HELPER
:
93 case task_manager::Resource::UNKNOWN
:
94 type
= keys::kProcessTypeOther
;
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
);
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
)
120 if (!widget
->IsRenderView())
123 content::RenderViewHost
* host
= content::RenderViewHost::From(widget
);
124 content::WebContents
* contents
=
125 content::WebContents::FromRenderViewHost(host
);
127 tab_id
= ExtensionTabUtil::GetTabId(contents
);
129 tabs_list
->Append(new base::FundamentalValue(tab_id
));
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
,
142 bool include_optional
) {
143 base::DictionaryValue
* result
= new base::DictionaryValue();
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
)
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 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.
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
));
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
,
204 int64 pr_mem
= model
->GetPrivateMemory(index
, &mem
) ?
205 static_cast<int64
>(mem
) : -1;
206 result
->SetDouble(keys::kPrivateMemoryKey
, static_cast<double>(pr_mem
));
209 #endif // defined(ENABLE_TASK_MANAGER)
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);
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)
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());
233 if (task_manager_listening_
)
234 model_
->StopListening();
236 model_
->RemoveObserver(this);
237 #endif // defined(ENABLE_TASK_MANAGER)
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)
249 void ProcessesEventRouter::ListenerRemoved() {
250 DCHECK_GT(listeners_
, 0);
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)
259 void ProcessesEventRouter::StartTaskManagerListening() {
260 #if defined(ENABLE_TASK_MANAGER)
261 if (!task_manager_listening_
) {
262 model_
->StartListening();
263 task_manager_listening_
= true;
265 #endif // defined(ENABLE_TASK_MANAGER)
268 void ProcessesEventRouter::Observe(
270 const content::NotificationSource
& source
,
271 const content::NotificationDetails
& details
) {
274 case content::NOTIFICATION_RENDER_WIDGET_HOST_HANG
:
276 content::Source
<content::RenderWidgetHost
>(source
).ptr());
278 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED
:
280 content::Source
<content::RenderProcessHost
>(source
).ptr(),
281 content::Details
<content::RenderProcessHost::RendererClosedDetails
>(
285 NOTREACHED() << "Unexpected observe of type " << type
;
290 void ProcessesEventRouter::OnItemsAdded(int start
, int length
) {
291 #if defined(ENABLE_TASK_MANAGER)
292 DCHECK_EQ(length
, 1);
295 std::string
event(keys::kOnCreated
);
296 if (!HasEventListeners(event
))
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
);
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
);
313 args
->Append(process
);
315 DispatchEvent(keys::kOnCreated
, args
.Pass());
316 #endif // defined(ENABLE_TASK_MANAGER)
319 void ProcessesEventRouter::OnItemsChanged(int start
, int length
) {
320 #if defined(ENABLE_TASK_MANAGER)
321 // If we don't have any listeners, return immediately.
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
);
335 DCHECK(updated
|| updated_memory
);
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
,
343 processes_map
.AddWithID(process
, i
);
348 std::string
idkey(keys::kIdKey
);
349 base::DictionaryValue
* processes
= new base::DictionaryValue();
352 IDMap
<base::DictionaryValue
>::iterator
it(&processes_map
);
353 for (; !it
.IsAtEnd(); it
.Advance()) {
354 if (!it
.GetCurrentValue()->GetInteger(idkey
, &id
))
357 // Store each process indexed by the string version of its id.
358 processes
->Set(base::IntToString(id
), it
.GetCurrentValue());
361 scoped_ptr
<base::ListValue
> args(new base::ListValue());
362 args
->Append(processes
);
363 DispatchEvent(keys::kOnUpdated
, args
.Pass());
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
))
372 AddMemoryDetails(it
.GetCurrentValue(), model_
, it
.GetCurrentKey());
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.
377 processes
->Set(base::IntToString(id
), it
.GetCurrentValue());
380 scoped_ptr
<base::ListValue
> args(new base::ListValue());
381 args
->Append(processes
);
382 DispatchEvent(keys::kOnUpdatedWithMemory
, args
.Pass());
384 #endif // defined(ENABLE_TASK_MANAGER)
387 void ProcessesEventRouter::OnItemsToBeRemoved(int start
, int length
) {
388 #if defined(ENABLE_TASK_MANAGER)
389 DCHECK_EQ(length
, 1);
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
395 if (model_
->GetResourceType(start
) == task_manager::Resource::RENDERER
)
398 // The callback function parameters.
399 scoped_ptr
<base::ListValue
> args(new base::ListValue());
401 // First arg: The id of the process that was closed.
402 args
->Append(new base::FundamentalValue(
403 model_
->GetUniqueChildProcessId(start
)));
405 // Second arg: The exit type for the process.
406 args
->Append(new base::FundamentalValue(0));
408 // Third arg: The exit code for the process.
409 args
->Append(new base::FundamentalValue(0));
411 DispatchEvent(keys::kOnExited
, args
.Pass());
412 #endif // defined(ENABLE_TASK_MANAGER)
415 void ProcessesEventRouter::ProcessHangEvent(content::RenderWidgetHost
* widget
) {
416 #if defined(ENABLE_TASK_MANAGER)
417 std::string
event(keys::kOnUnresponsive
);
418 if (!HasEventListeners(event
))
421 base::DictionaryValue
* process
= NULL
;
422 int count
= model_
->ResourceCount();
423 int id
= widget
->GetProcess()->GetID();
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);
437 scoped_ptr
<base::ListValue
> args(new base::ListValue());
438 args
->Append(process
);
440 DispatchEvent(keys::kOnUnresponsive
, args
.Pass());
441 #endif // defined(ENABLE_TASK_MANAGER)
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());
451 // First arg: The id of the process that was closed.
452 args
->Append(new base::FundamentalValue(rph
->GetID()));
454 // Second arg: The exit type for the process.
455 args
->Append(new base::FundamentalValue(details
->status
));
457 // Third arg: The exit code for the process.
458 args
->Append(new base::FundamentalValue(details
->exit_code
));
460 DispatchEvent(keys::kOnExited
, args
.Pass());
461 #endif // defined(ENABLE_TASK_MANAGER)
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_
);
469 scoped_ptr
<extensions::Event
> event(new extensions::Event(
470 event_name
, event_args
.Pass()));
471 event_router
->BroadcastEvent(event
.Pass());
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
);
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
>();
493 ProcessesAPI::~ProcessesAPI() {
496 void ProcessesAPI::Shutdown() {
497 EventRouter::Get(browser_context_
)->UnregisterObserver(this);
500 static base::LazyInstance
<BrowserContextKeyedAPIFactory
<ProcessesAPI
> >
501 g_factory
= LAZY_INSTANCE_INITIALIZER
;
504 BrowserContextKeyedAPIFactory
<ProcessesAPI
>*
505 ProcessesAPI::GetFactoryInstance() {
506 return g_factory
.Pointer();
510 ProcessesAPI
* ProcessesAPI::Get(content::BrowserContext
* context
) {
511 return BrowserContextKeyedAPIFactory
<ProcessesAPI
>::Get(context
);
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();
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();
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();
533 GetProcessIdForTabFunction::GetProcessIdForTabFunction() : tab_id_(-1) {
536 bool GetProcessIdForTabFunction::RunAsync() {
537 #if defined(ENABLE_TASK_MANAGER)
538 EXTENSION_FUNCTION_VALIDATE(args_
->GetInteger(0, &tab_id_
));
540 // Add a reference, which is balanced in GetProcessIdForTab to keep the object
541 // around and allow for the callback to be invoked.
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));
554 TaskManager::GetInstance()->model()->RegisterOnDataReadyCallback(
555 base::Bind(&GetProcessIdForTabFunction::GetProcessIdForTab
, this));
557 ProcessesAPI::Get(GetProfile())
558 ->processes_event_router()
559 ->StartTaskManagerListening();
564 error_
= errors::kExtensionNotSupported
;
566 #endif // defined(ENABLE_TASK_MANAGER)
569 void GetProcessIdForTabFunction::GetProcessIdForTab() {
570 content::WebContents
* contents
= NULL
;
572 if (!ExtensionTabUtil::GetTabById(tab_id_
,
579 error_
= ErrorUtils::FormatErrorMessage(
580 extensions::tabs_constants::kTabNotFoundError
,
581 base::IntToString(tab_id_
));
582 SetResult(new base::FundamentalValue(-1));
585 int process_id
= contents
->GetRenderProcessHost()->GetID();
586 SetResult(new base::FundamentalValue(process_id
));
590 // Balance the AddRef in the RunAsync.
594 TerminateFunction::TerminateFunction() : process_id_(-1) {
597 bool TerminateFunction::RunAsync() {
598 #if defined(ENABLE_TASK_MANAGER)
599 EXTENSION_FUNCTION_VALIDATE(args_
->GetInteger(0, &process_id_
));
601 // Add a reference, which is balanced in TerminateProcess to keep the object
602 // around and allow for the callback to be invoked.
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));
615 TaskManager::GetInstance()->model()->RegisterOnDataReadyCallback(
616 base::Bind(&TerminateFunction::TerminateProcess
, this));
618 ProcessesAPI::Get(GetProfile())
619 ->processes_event_router()
620 ->StartTaskManagerListening();
625 error_
= errors::kExtensionNotSupported
;
627 #endif // defined(ENABLE_TASK_MANAGER)
631 void TerminateFunction::TerminateProcess() {
632 #if defined(ENABLE_TASK_MANAGER)
633 TaskManagerModel
* model
= TaskManager::GetInstance()->model();
635 int count
= model
->ResourceCount();
639 for (int i
= 0; i
< count
; ++i
) {
640 if (model
->IsResourceFirstInGroup(i
)) {
641 if (process_id_
== model
->GetUniqueChildProcessId(i
)) {
643 killed
= base::KillProcess(model
->GetProcess(i
),
644 content::RESULT_CODE_KILLED
, true);
645 UMA_HISTOGRAM_COUNTS("ChildProcess.KilledByExtensionAPI", 1);
652 error_
= ErrorUtils::FormatErrorMessage(errors::kProcessNotFound
,
653 base::IntToString(process_id_
));
656 SetResult(new base::FundamentalValue(killed
));
660 // Balance the AddRef in the RunAsync.
663 error_
= errors::kExtensionNotSupported
;
665 #endif // defined(ENABLE_TASK_MANAGER)
668 GetProcessInfoFunction::GetProcessInfoFunction()
669 #if defined(ENABLE_TASK_MANAGER)
675 GetProcessInfoFunction::~GetProcessInfoFunction() {
678 bool GetProcessInfoFunction::RunAsync() {
679 #if defined(ENABLE_TASK_MANAGER)
680 base::Value
* processes
= NULL
;
682 EXTENSION_FUNCTION_VALIDATE(args_
->Get(0, &processes
));
683 EXTENSION_FUNCTION_VALIDATE(args_
->GetBoolean(1, &memory_
));
685 EXTENSION_FUNCTION_VALIDATE(extensions::ReadOneOrMoreIntegers(
686 processes
, &process_ids_
));
688 // Add a reference, which is balanced in GatherProcessInfo to keep the object
689 // around and allow for the callback to be invoked.
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));
702 TaskManager::GetInstance()->model()->RegisterOnDataReadyCallback(
703 base::Bind(&GetProcessInfoFunction::GatherProcessInfo
, this));
705 ProcessesAPI::Get(GetProfile())
706 ->processes_event_router()
707 ->StartTaskManagerListening();
712 error_
= errors::kExtensionNotSupported
;
714 #endif // defined(ENABLE_TASK_MANAGER)
717 void GetProcessInfoFunction::GatherProcessInfo() {
718 #if defined(ENABLE_TASK_MANAGER)
719 TaskManagerModel
* model
= TaskManager::GetInstance()->model();
720 base::DictionaryValue
* processes
= new base::DictionaryValue();
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);
731 AddMemoryDetails(d
, model
, i
);
732 processes
->Set(base::IntToString(id
), d
);
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);
746 AddMemoryDetails(d
, model
, i
);
747 processes
->Set(base::IntToString(id
), d
);
749 process_ids_
.erase(proc_id
);
750 if (process_ids_
.size() == 0)
755 DCHECK_EQ(process_ids_
.size(), 0U);
758 SetResult(processes
);
761 // Balance the AddRef in the RunAsync.
763 #endif // defined(ENABLE_TASK_MANAGER)
766 } // namespace extensions