Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(873)

Side by Side Diff: chrome/browser/extensions/extension_processes_api.cc

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

Powered by Google App Engine
This is Rietveld 408576698