blob: eb20dacb7cad8e1f5cc880fe451b83e89f31f88e [file] [log] [blame]
[email protected]4abb4602012-03-16 01:59:551// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]381162b2010-01-28 17:29:352// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]bc500fa2012-09-06 09:03:305#include "chrome/browser/extensions/api/processes/processes_api.h"
[email protected]381162b2010-01-28 17:29:356
[email protected]8a661f82010-10-19 21:47:117#include "base/callback.h"
8#include "base/json/json_writer.h"
[email protected]01d0ffd2012-12-26 23:22:519#include "base/lazy_instance.h"
[email protected]8a661f82010-10-19 21:47:1110#include "base/message_loop.h"
[email protected]350584cd2012-05-17 18:18:2611#include "base/metrics/histogram.h"
[email protected]8a661f82010-10-19 21:47:1112#include "base/string_number_conversions.h"
[email protected]8a661f82010-10-19 21:47:1113#include "base/utf_string_conversions.h"
[email protected]c02c853d72010-08-07 06:23:2414#include "base/values.h"
[email protected]bc500fa2012-09-06 09:03:3015#include "chrome/browser/extensions/api/processes/processes_api_constants.h"
[email protected]b19451b2012-06-08 17:36:1916#include "chrome/browser/extensions/api/tabs/tabs_constants.h"
[email protected]5a38dfd2012-07-23 23:22:1017#include "chrome/browser/extensions/event_router.h"
[email protected]8e0438a72012-12-05 02:17:4218#include "chrome/browser/extensions/extension_function_registry.h"
[email protected]350584cd2012-05-17 18:18:2619#include "chrome/browser/extensions/extension_function_util.h"
[email protected]350584cd2012-05-17 18:18:2620#include "chrome/browser/extensions/extension_service.h"
[email protected]9e5be1f92012-10-29 19:01:4521#include "chrome/browser/extensions/extension_system.h"
[email protected]ac84431b2011-09-27 17:26:1122#include "chrome/browser/extensions/extension_tab_util.h"
[email protected]8ecad5e2010-12-02 21:18:3323#include "chrome/browser/profiles/profile.h"
[email protected]8a661f82010-10-19 21:47:1124#include "chrome/browser/task_manager/task_manager.h"
[email protected]350584cd2012-05-17 18:18:2625#include "chrome/common/chrome_notification_types.h"
[email protected]350584cd2012-05-17 18:18:2626#include "content/public/browser/notification_details.h"
27#include "content/public/browser/notification_service.h"
28#include "content/public/browser/notification_source.h"
[email protected]0d6e9bd2011-10-18 04:29:1629#include "content/public/browser/notification_types.h"
[email protected]f3b1a082011-11-18 00:34:3030#include "content/public/browser/render_process_host.h"
[email protected]350584cd2012-05-17 18:18:2631#include "content/public/browser/render_view_host.h"
[email protected]350584cd2012-05-17 18:18:2632#include "content/public/browser/render_widget_host.h"
[email protected]ef9572e2012-01-04 22:14:1233#include "content/public/browser/web_contents.h"
[email protected]350584cd2012-05-17 18:18:2634#include "content/public/common/result_codes.h"
[email protected]e9f541a2012-11-19 21:52:3135#include "extensions/common/error_utils.h"
[email protected]381162b2010-01-28 17:29:3536
[email protected]bc500fa2012-09-06 09:03:3037namespace extensions {
38
39namespace keys = processes_api_constants;
40namespace errors = processes_api_constants;
[email protected]381162b2010-01-28 17:29:3541
[email protected]350584cd2012-05-17 18:18:2642namespace {
43
44#if defined(ENABLE_TASK_MANAGER)
45
46DictionaryValue* CreateCacheData(
47 const WebKit::WebCache::ResourceTypeStat& stat) {
48
49 DictionaryValue* cache = new DictionaryValue();
50 cache->SetDouble(keys::kCacheSize, static_cast<double>(stat.size));
51 cache->SetDouble(keys::kCacheLiveSize, static_cast<double>(stat.liveSize));
52 return cache;
53}
54
55void SetProcessType(DictionaryValue* result,
56 TaskManagerModel* model,
57 int index) {
58 // Determine process type.
59 std::string type = keys::kProcessTypeOther;
60 TaskManager::Resource::Type resource_type = model->GetResourceType(index);
61 switch (resource_type) {
62 case TaskManager::Resource::BROWSER:
63 type = keys::kProcessTypeBrowser;
64 break;
65 case TaskManager::Resource::RENDERER:
66 type = keys::kProcessTypeRenderer;
67 break;
68 case TaskManager::Resource::EXTENSION:
69 type = keys::kProcessTypeExtension;
70 break;
71 case TaskManager::Resource::NOTIFICATION:
72 type = keys::kProcessTypeNotification;
73 break;
74 case TaskManager::Resource::PLUGIN:
75 type = keys::kProcessTypePlugin;
76 break;
77 case TaskManager::Resource::WORKER:
78 type = keys::kProcessTypeWorker;
79 break;
80 case TaskManager::Resource::NACL:
81 type = keys::kProcessTypeNacl;
82 break;
83 case TaskManager::Resource::UTILITY:
84 type = keys::kProcessTypeUtility;
85 break;
86 case TaskManager::Resource::GPU:
87 type = keys::kProcessTypeGPU;
88 break;
89 case TaskManager::Resource::PROFILE_IMPORT:
90 case TaskManager::Resource::ZYGOTE:
91 case TaskManager::Resource::SANDBOX_HELPER:
92 case TaskManager::Resource::UNKNOWN:
93 type = keys::kProcessTypeOther;
94 break;
95 default:
96 NOTREACHED() << "Unknown resource type.";
97 }
[email protected]8a661f82010-10-19 21:47:1198 result->SetString(keys::kTypeKey, type);
[email protected]350584cd2012-05-17 18:18:2699}
100
101ListValue* GetTabsForProcess(int process_id) {
102 ListValue* tabs_list = new ListValue();
103
104 // The tabs list only makes sense for render processes, so if we don't find
105 // one, just return the empty list.
106 content::RenderProcessHost* rph =
107 content::RenderProcessHost::FromID(process_id);
108 if (rph == NULL)
109 return tabs_list;
110
111 int tab_id = -1;
112 // We need to loop through all the RVHs to ensure we collect the set of all
113 // tabs using this renderer process.
114 content::RenderProcessHost::RenderWidgetHostsIterator iter(
115 rph->GetRenderWidgetHostsIterator());
116 for (; !iter.IsAtEnd(); iter.Advance()) {
117 const content::RenderWidgetHost* widget = iter.GetCurrentValue();
118 DCHECK(widget);
119 if (!widget || !widget->IsRenderView())
120 continue;
121
122 content::RenderViewHost* host = content::RenderViewHost::From(
123 const_cast<content::RenderWidgetHost*>(widget));
[email protected]746d3052012-05-22 15:15:47124 content::WebContents* contents =
125 content::WebContents::FromRenderViewHost(host);
126 if (contents) {
[email protected]350584cd2012-05-17 18:18:26127 tab_id = ExtensionTabUtil::GetTabId(contents);
128 if (tab_id != -1)
129 tabs_list->Append(Value::CreateIntegerValue(tab_id));
130 }
131 }
132
133 return tabs_list;
134}
135
136// This function creates a Process object to be returned to the extensions
137// using these APIs. For memory details, which are not added by this function,
138// the callers need to use AddMemoryDetails.
139DictionaryValue* CreateProcessFromModel(int process_id,
140 TaskManagerModel* model,
141 int index,
142 bool include_optional) {
143 DictionaryValue* result = new DictionaryValue();
144 size_t mem;
145
146 result->SetInteger(keys::kIdKey, process_id);
147 result->SetInteger(keys::kOsProcessIdKey, model->GetProcessId(index));
148 SetProcessType(result, model, index);
149 result->SetString(keys::kProfileKey,
150 model->GetResourceProfileName(index));
151
152 result->Set(keys::kTabsListKey, GetTabsForProcess(process_id));
153
154 // If we don't need to include the optional properties, just return now.
155 if (!include_optional)
156 return result;
157
158 result->SetDouble(keys::kCpuKey, model->GetCPUUsage(index));
159
160 if (model->GetV8Memory(index, &mem))
161 result->SetDouble(keys::kJsMemoryAllocatedKey,
162 static_cast<double>(mem));
163
164 if (model->GetV8MemoryUsed(index, &mem))
165 result->SetDouble(keys::kJsMemoryUsedKey,
166 static_cast<double>(mem));
167
168 if (model->GetSqliteMemoryUsedBytes(index, &mem))
169 result->SetDouble(keys::kSqliteMemoryKey,
170 static_cast<double>(mem));
171
172 WebKit::WebCache::ResourceTypeStats cache_stats;
173 if (model->GetWebCoreCacheStats(index, &cache_stats)) {
174 result->Set(keys::kImageCacheKey,
175 CreateCacheData(cache_stats.images));
176 result->Set(keys::kScriptCacheKey,
177 CreateCacheData(cache_stats.scripts));
178 result->Set(keys::kCssCacheKey,
179 CreateCacheData(cache_stats.cssStyleSheets));
180 }
181
182 // Network and FPS are reported by the TaskManager per resource (tab), not
183 // per process, therefore we need to iterate through the group of resources
184 // and aggregate the data.
185 float fps = 0, tmp = 0;
186 int64 net = 0;
187 int length = model->GetGroupRangeForResource(index).second;
188 for (int i = 0; i < length; ++i) {
189 net += model->GetNetworkUsage(index + i);
190 if (model->GetFPS(index + i, &tmp))
191 fps += tmp;
192 }
193 result->SetDouble(keys::kFPSKey, static_cast<double>(fps));
[email protected]fb534c92011-02-01 01:02:07194 result->SetDouble(keys::kNetworkKey, static_cast<double>(net));
[email protected]350584cd2012-05-17 18:18:26195
[email protected]381162b2010-01-28 17:29:35196 return result;
197}
198
[email protected]350584cd2012-05-17 18:18:26199// 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.
202void AddMemoryDetails(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));
209}
210
211#endif // defined(ENABLE_TASK_MANAGER)
212
[email protected]79a60642012-10-20 21:03:18213} // namespace
[email protected]350584cd2012-05-17 18:18:26214
[email protected]c4dc5cc2012-11-09 08:48:39215ProcessesEventRouter::ProcessesEventRouter(Profile* profile)
216 : profile_(profile),
217 listeners_(0),
[email protected]350584cd2012-05-17 18:18:26218 task_manager_listening_(false) {
[email protected]043771a2012-04-23 20:20:38219#if defined(ENABLE_TASK_MANAGER)
[email protected]7da9a8232011-05-27 21:07:11220 model_ = TaskManager::GetInstance()->model();
221 model_->AddObserver(this);
[email protected]350584cd2012-05-17 18:18:26222
223 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_HANG,
224 content::NotificationService::AllSources());
225 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
226 content::NotificationService::AllSources());
[email protected]043771a2012-04-23 20:20:38227#endif // defined(ENABLE_TASK_MANAGER)
[email protected]8a661f82010-10-19 21:47:11228}
229
[email protected]bc500fa2012-09-06 09:03:30230ProcessesEventRouter::~ProcessesEventRouter() {
[email protected]043771a2012-04-23 20:20:38231#if defined(ENABLE_TASK_MANAGER)
[email protected]350584cd2012-05-17 18:18:26232 registrar_.Remove(this, content::NOTIFICATION_RENDERER_PROCESS_HANG,
233 content::NotificationService::AllSources());
234 registrar_.Remove(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
235 content::NotificationService::AllSources());
236
237 if (task_manager_listening_)
238 model_->StopListening();
239
[email protected]8a661f82010-10-19 21:47:11240 model_->RemoveObserver(this);
[email protected]043771a2012-04-23 20:20:38241#endif // defined(ENABLE_TASK_MANAGER)
[email protected]8a661f82010-10-19 21:47:11242}
243
[email protected]bc500fa2012-09-06 09:03:30244void ProcessesEventRouter::ListenerAdded() {
[email protected]043771a2012-04-23 20:20:38245#if defined(ENABLE_TASK_MANAGER)
[email protected]350584cd2012-05-17 18:18:26246 // The task manager has its own ref count to balance other callers of
247 // StartUpdating/StopUpdating.
[email protected]8a661f82010-10-19 21:47:11248 model_->StartUpdating();
[email protected]043771a2012-04-23 20:20:38249#endif // defined(ENABLE_TASK_MANAGER)
[email protected]350584cd2012-05-17 18:18:26250 ++listeners_;
[email protected]8a661f82010-10-19 21:47:11251}
252
[email protected]bc500fa2012-09-06 09:03:30253void ProcessesEventRouter::ListenerRemoved() {
[email protected]79a60642012-10-20 21:03:18254 DCHECK_GT(listeners_, 0);
[email protected]350584cd2012-05-17 18:18:26255 --listeners_;
[email protected]043771a2012-04-23 20:20:38256#if defined(ENABLE_TASK_MANAGER)
[email protected]350584cd2012-05-17 18:18:26257 // The task manager has its own ref count to balance other callers of
258 // StartUpdating/StopUpdating.
[email protected]8a661f82010-10-19 21:47:11259 model_->StopUpdating();
[email protected]043771a2012-04-23 20:20:38260#endif // defined(ENABLE_TASK_MANAGER)
[email protected]8a661f82010-10-19 21:47:11261}
262
[email protected]bc500fa2012-09-06 09:03:30263void ProcessesEventRouter::StartTaskManagerListening() {
[email protected]350584cd2012-05-17 18:18:26264#if defined(ENABLE_TASK_MANAGER)
265 if (!task_manager_listening_) {
266 model_->StartListening();
267 task_manager_listening_ = true;
268 }
269#endif // defined(ENABLE_TASK_MANAGER)
270}
271
[email protected]bc500fa2012-09-06 09:03:30272void ProcessesEventRouter::Observe(
[email protected]350584cd2012-05-17 18:18:26273 int type,
274 const content::NotificationSource& source,
275 const content::NotificationDetails& details) {
276
277 switch (type) {
278 case content::NOTIFICATION_RENDERER_PROCESS_HANG:
279 ProcessHangEvent(
280 content::Source<content::RenderWidgetHost>(source).ptr());
281 break;
282 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED:
283 ProcessClosedEvent(
284 content::Source<content::RenderProcessHost>(source).ptr(),
285 content::Details<content::RenderProcessHost::RendererClosedDetails>(
286 details).ptr());
287 break;
288 default:
289 NOTREACHED() << "Unexpected observe of type " << type;
290 }
291 return;
292}
293
[email protected]bc500fa2012-09-06 09:03:30294void ProcessesEventRouter::OnItemsAdded(int start, int length) {
[email protected]350584cd2012-05-17 18:18:26295#if defined(ENABLE_TASK_MANAGER)
296 DCHECK_EQ(length, 1);
297 int index = start;
298
299 std::string event(keys::kOnCreated);
300 if (!HasEventListeners(event))
301 return;
302
303 // If the item being added is not the first one in the group, find the base
304 // index and use it for retrieving the process data.
305 if (!model_->IsResourceFirstInGroup(start)) {
306 index = model_->GetGroupIndexForResource(start);
307 }
308
[email protected]c9bd90f2012-08-07 23:58:15309 scoped_ptr<ListValue> args(new ListValue());
[email protected]350584cd2012-05-17 18:18:26310 DictionaryValue* process = CreateProcessFromModel(
311 model_->GetUniqueChildProcessId(index), model_, index, false);
312 DCHECK(process != NULL);
313
314 if (process == NULL)
315 return;
316
[email protected]c9bd90f2012-08-07 23:58:15317 args->Append(process);
[email protected]350584cd2012-05-17 18:18:26318
[email protected]c4dc5cc2012-11-09 08:48:39319 DispatchEvent(keys::kOnCreated, args.Pass());
[email protected]350584cd2012-05-17 18:18:26320#endif // defined(ENABLE_TASK_MANAGER)
321}
322
[email protected]bc500fa2012-09-06 09:03:30323void ProcessesEventRouter::OnItemsChanged(int start, int length) {
[email protected]043771a2012-04-23 20:20:38324#if defined(ENABLE_TASK_MANAGER)
[email protected]350584cd2012-05-17 18:18:26325 // If we don't have any listeners, return immediately.
326 if (listeners_ == 0)
327 return;
[email protected]8a661f82010-10-19 21:47:11328
[email protected]350584cd2012-05-17 18:18:26329 if (!model_)
330 return;
[email protected]8a661f82010-10-19 21:47:11331
[email protected]350584cd2012-05-17 18:18:26332 // We need to know which type of onUpdated events to fire and whether to
333 // collect memory or not.
334 std::string updated_event(keys::kOnUpdated);
335 std::string updated_event_memory(keys::kOnUpdatedWithMemory);
336 bool updated = HasEventListeners(updated_event);
337 bool updated_memory = HasEventListeners(updated_event_memory);
[email protected]8a661f82010-10-19 21:47:11338
[email protected]350584cd2012-05-17 18:18:26339 DCHECK(updated || updated_memory);
[email protected]8a661f82010-10-19 21:47:11340
[email protected]350584cd2012-05-17 18:18:26341 IDMap<DictionaryValue> processes_map;
342 for (int i = start; i < start + length; i++) {
343 if (model_->IsResourceFirstInGroup(i)) {
344 int id = model_->GetUniqueChildProcessId(i);
345 DictionaryValue* process = CreateProcessFromModel(id, model_, i, true);
346 processes_map.AddWithID(process, i);
[email protected]8a661f82010-10-19 21:47:11347 }
[email protected]350584cd2012-05-17 18:18:26348 }
[email protected]8a661f82010-10-19 21:47:11349
[email protected]350584cd2012-05-17 18:18:26350 int id;
351 std::string idkey(keys::kIdKey);
352 DictionaryValue* processes = new DictionaryValue();
353
354 if (updated) {
355 IDMap<DictionaryValue>::iterator it(&processes_map);
356 for (; !it.IsAtEnd(); it.Advance()) {
357 if (!it.GetCurrentValue()->GetInteger(idkey, &id))
358 continue;
359
360 // Store each process indexed by the string version of its id.
361 processes->Set(base::IntToString(id), it.GetCurrentValue());
362 }
363
[email protected]c9bd90f2012-08-07 23:58:15364 scoped_ptr<ListValue> args(new ListValue());
365 args->Append(processes);
[email protected]c4dc5cc2012-11-09 08:48:39366 DispatchEvent(keys::kOnUpdated, args.Pass());
[email protected]350584cd2012-05-17 18:18:26367 }
[email protected]8a661f82010-10-19 21:47:11368
[email protected]350584cd2012-05-17 18:18:26369 if (updated_memory) {
370 IDMap<DictionaryValue>::iterator it(&processes_map);
371 for (; !it.IsAtEnd(); it.Advance()) {
372 if (!it.GetCurrentValue()->GetInteger(idkey, &id))
373 continue;
374
375 AddMemoryDetails(it.GetCurrentValue(), model_, it.GetCurrentKey());
376
377 // Store each process indexed by the string version of its id if we didn't
378 // already insert it as part of the onUpdated processing above.
379 if (!updated)
380 processes->Set(base::IntToString(id), it.GetCurrentValue());
[email protected]7da9a8232011-05-27 21:07:11381 }
[email protected]350584cd2012-05-17 18:18:26382
[email protected]c9bd90f2012-08-07 23:58:15383 scoped_ptr<ListValue> args(new ListValue());
384 args->Append(processes);
[email protected]c4dc5cc2012-11-09 08:48:39385 DispatchEvent(keys::kOnUpdatedWithMemory, args.Pass());
[email protected]8a661f82010-10-19 21:47:11386 }
[email protected]043771a2012-04-23 20:20:38387#endif // defined(ENABLE_TASK_MANAGER)
[email protected]8a661f82010-10-19 21:47:11388}
389
[email protected]bc500fa2012-09-06 09:03:30390void ProcessesEventRouter::OnItemsToBeRemoved(int start, int length) {
[email protected]350584cd2012-05-17 18:18:26391#if defined(ENABLE_TASK_MANAGER)
[email protected]79a60642012-10-20 21:03:18392 DCHECK_EQ(length, 1);
[email protected]350584cd2012-05-17 18:18:26393
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) == TaskManager::Resource::RENDERER)
399 return;
400
401 // The callback function parameters.
[email protected]c9bd90f2012-08-07 23:58:15402 scoped_ptr<ListValue> args(new ListValue());
[email protected]350584cd2012-05-17 18:18:26403
404 // First arg: The id of the process that was closed.
[email protected]c9bd90f2012-08-07 23:58:15405 args->Append(Value::CreateIntegerValue(
[email protected]350584cd2012-05-17 18:18:26406 model_->GetUniqueChildProcessId(start)));
407
408 // Second arg: The exit type for the process.
[email protected]c9bd90f2012-08-07 23:58:15409 args->Append(Value::CreateIntegerValue(0));
[email protected]350584cd2012-05-17 18:18:26410
411 // Third arg: The exit code for the process.
[email protected]c9bd90f2012-08-07 23:58:15412 args->Append(Value::CreateIntegerValue(0));
[email protected]350584cd2012-05-17 18:18:26413
[email protected]c4dc5cc2012-11-09 08:48:39414 DispatchEvent(keys::kOnExited, args.Pass());
[email protected]350584cd2012-05-17 18:18:26415#endif // defined(ENABLE_TASK_MANAGER)
416}
417
[email protected]bc500fa2012-09-06 09:03:30418void ProcessesEventRouter::ProcessHangEvent(content::RenderWidgetHost* widget) {
[email protected]350584cd2012-05-17 18:18:26419#if defined(ENABLE_TASK_MANAGER)
420 std::string event(keys::kOnUnresponsive);
421 if (!HasEventListeners(event))
422 return;
423
424 DictionaryValue* process = NULL;
425 int count = model_->ResourceCount();
426 int id = widget->GetProcess()->GetID();
427
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;
433 }
434 }
435 }
436
437 DCHECK(process);
438 if (process == NULL)
439 return;
440
[email protected]c9bd90f2012-08-07 23:58:15441 scoped_ptr<ListValue> args(new ListValue());
442 args->Append(process);
[email protected]350584cd2012-05-17 18:18:26443
[email protected]c4dc5cc2012-11-09 08:48:39444 DispatchEvent(keys::kOnUnresponsive, args.Pass());
[email protected]350584cd2012-05-17 18:18:26445#endif // defined(ENABLE_TASK_MANAGER)
446}
447
[email protected]bc500fa2012-09-06 09:03:30448void ProcessesEventRouter::ProcessClosedEvent(
[email protected]350584cd2012-05-17 18:18:26449 content::RenderProcessHost* rph,
450 content::RenderProcessHost::RendererClosedDetails* details) {
451#if defined(ENABLE_TASK_MANAGER)
452 // The callback function parameters.
[email protected]c9bd90f2012-08-07 23:58:15453 scoped_ptr<ListValue> args(new ListValue());
[email protected]350584cd2012-05-17 18:18:26454
455 // First arg: The id of the process that was closed.
[email protected]c9bd90f2012-08-07 23:58:15456 args->Append(Value::CreateIntegerValue(rph->GetID()));
[email protected]350584cd2012-05-17 18:18:26457
458 // Second arg: The exit type for the process.
[email protected]c9bd90f2012-08-07 23:58:15459 args->Append(Value::CreateIntegerValue(details->status));
[email protected]350584cd2012-05-17 18:18:26460
461 // Third arg: The exit code for the process.
[email protected]c9bd90f2012-08-07 23:58:15462 args->Append(Value::CreateIntegerValue(details->exit_code));
[email protected]350584cd2012-05-17 18:18:26463
[email protected]c4dc5cc2012-11-09 08:48:39464 DispatchEvent(keys::kOnExited, args.Pass());
[email protected]350584cd2012-05-17 18:18:26465#endif // defined(ENABLE_TASK_MANAGER)
466}
467
[email protected]c4dc5cc2012-11-09 08:48:39468void ProcessesEventRouter::DispatchEvent(const char* event_name,
[email protected]bc500fa2012-09-06 09:03:30469 scoped_ptr<ListValue> event_args) {
[email protected]c4dc5cc2012-11-09 08:48:39470 if (extensions::ExtensionSystem::Get(profile_)->event_router()) {
[email protected]01f7a8042012-12-07 07:48:02471 scoped_ptr<extensions::Event> event(new extensions::Event(
472 event_name, event_args.Pass()));
[email protected]c4dc5cc2012-11-09 08:48:39473 extensions::ExtensionSystem::Get(profile_)->event_router()->
[email protected]01f7a8042012-12-07 07:48:02474 BroadcastEvent(event.Pass());
[email protected]8a661f82010-10-19 21:47:11475 }
476}
477
[email protected]c4dc5cc2012-11-09 08:48:39478bool ProcessesEventRouter::HasEventListeners(const std::string& event_name) {
479 extensions::EventRouter* router =
480 extensions::ExtensionSystem::Get(profile_)->event_router();
[email protected]f05c4fc22012-12-09 09:25:21481 if (router && router->HasEventListener(event_name))
482 return true;
[email protected]c4dc5cc2012-11-09 08:48:39483 return false;
[email protected]d81d3a192012-11-09 00:32:50484}
485
[email protected]c4dc5cc2012-11-09 08:48:39486ProcessesAPI::ProcessesAPI(Profile* profile) : profile_(profile) {
487 ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
488 this, processes_api_constants::kOnUpdated);
489 ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
490 this, processes_api_constants::kOnUpdatedWithMemory);
[email protected]8e0438a72012-12-05 02:17:42491 ExtensionFunctionRegistry* registry =
492 ExtensionFunctionRegistry::GetInstance();
493 registry->RegisterFunction<extensions::GetProcessIdForTabFunction>();
494 registry->RegisterFunction<extensions::TerminateFunction>();
495 registry->RegisterFunction<extensions::GetProcessInfoFunction>();
[email protected]c4dc5cc2012-11-09 08:48:39496}
[email protected]d81d3a192012-11-09 00:32:50497
[email protected]c4dc5cc2012-11-09 08:48:39498ProcessesAPI::~ProcessesAPI() {
499}
500
501void ProcessesAPI::Shutdown() {
502 ExtensionSystem::Get(profile_)->event_router()->UnregisterObserver(this);
503}
504
[email protected]c39df1a2013-01-08 18:22:07505static base::LazyInstance<ProfileKeyedAPIFactory<ProcessesAPI> >
506g_factory = LAZY_INSTANCE_INITIALIZER;
507
508// static
509ProfileKeyedAPIFactory<ProcessesAPI>* ProcessesAPI::GetFactoryInstance() {
510 return &g_factory.Get();
511}
512
[email protected]c4dc5cc2012-11-09 08:48:39513// static
514ProcessesAPI* ProcessesAPI::Get(Profile* profile) {
[email protected]01d0ffd2012-12-26 23:22:51515 return ProfileKeyedAPIFactory<ProcessesAPI>::GetForProfile(profile);
[email protected]c4dc5cc2012-11-09 08:48:39516}
517
518ProcessesEventRouter* ProcessesAPI::processes_event_router() {
519 if (!processes_event_router_)
520 processes_event_router_.reset(new ProcessesEventRouter(profile_));
521 return processes_event_router_.get();
522}
523
[email protected]954e13492012-11-15 03:18:23524void ProcessesAPI::OnListenerAdded(const EventListenerInfo& details) {
[email protected]c4dc5cc2012-11-09 08:48:39525 // We lazily tell the TaskManager to start updating when listeners to the
526 // processes.onUpdated or processes.onUpdatedWithMemory events arrive.
527 processes_event_router()->ListenerAdded();
528}
529
[email protected]954e13492012-11-15 03:18:23530void ProcessesAPI::OnListenerRemoved(const EventListenerInfo& details) {
[email protected]c4dc5cc2012-11-09 08:48:39531 // If a processes.onUpdated or processes.onUpdatedWithMemory event listener
532 // is removed (or a process with one exits), then we let the extension API
533 // know that it has one fewer listener.
534 processes_event_router()->ListenerRemoved();
[email protected]350584cd2012-05-17 18:18:26535}
[email protected]381162b2010-01-28 17:29:35536
[email protected]ef3f4f92012-10-05 03:28:29537GetProcessIdForTabFunction::GetProcessIdForTabFunction() : tab_id_(-1) {
538}
539
[email protected]350584cd2012-05-17 18:18:26540bool GetProcessIdForTabFunction::RunImpl() {
541#if defined(ENABLE_TASK_MANAGER)
542 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &tab_id_));
543
544 // Add a reference, which is balanced in GetProcessIdForTab to keep the object
545 // around and allow for the callback to be invoked.
546 AddRef();
547
548 // If the task manager is already listening, just post a task to execute
549 // which will invoke the callback once we have returned from this function.
550 // Otherwise, wait for the notification that the task manager is done with
551 // the data gathering.
[email protected]c4dc5cc2012-11-09 08:48:39552 if (ProcessesAPI::Get(profile_)->processes_event_router()->
553 is_task_manager_listening()) {
[email protected]350584cd2012-05-17 18:18:26554 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
555 &GetProcessIdForTabFunction::GetProcessIdForTab, this));
556 } else {
557 registrar_.Add(this,
558 chrome::NOTIFICATION_TASK_MANAGER_CHILD_PROCESSES_DATA_READY,
559 content::NotificationService::AllSources());
[email protected]c4dc5cc2012-11-09 08:48:39560 ProcessesAPI::Get(profile_)->processes_event_router()->
561 StartTaskManagerListening();
[email protected]350584cd2012-05-17 18:18:26562 }
563
564 return true;
565#else
[email protected]c92dd3f2012-06-20 19:49:58566 error_ = errors::kExtensionNotSupported;
[email protected]350584cd2012-05-17 18:18:26567 return false;
568#endif // defined(ENABLE_TASK_MANAGER)
569}
570
571void GetProcessIdForTabFunction::Observe(
572 int type,
573 const content::NotificationSource& source,
574 const content::NotificationDetails& details) {
575 DCHECK_EQ(type, chrome::NOTIFICATION_TASK_MANAGER_CHILD_PROCESSES_DATA_READY);
576 registrar_.RemoveAll();
577 GetProcessIdForTab();
578}
579
580void GetProcessIdForTabFunction::GetProcessIdForTab() {
[email protected]72f67972012-10-30 18:53:28581 content::WebContents* contents = NULL;
[email protected]381162b2010-01-28 17:29:35582 int tab_index = -1;
[email protected]350584cd2012-05-17 18:18:26583 if (!ExtensionTabUtil::GetTabById(tab_id_, profile(), include_incognito(),
[email protected]8a661f82010-10-19 21:47:11584 NULL, NULL, &contents, &tab_index)) {
[email protected]e9f541a2012-11-19 21:52:31585 error_ = ErrorUtils::FormatErrorMessage(
[email protected]b19451b2012-06-08 17:36:19586 extensions::tabs_constants::kTabNotFoundError,
[email protected]350584cd2012-05-17 18:18:26587 base::IntToString(tab_id_));
[email protected]07ff5fd2012-07-12 22:39:09588 SetResult(Value::CreateIntegerValue(-1));
[email protected]350584cd2012-05-17 18:18:26589 SendResponse(false);
590 } else {
[email protected]72f67972012-10-30 18:53:28591 int process_id = contents->GetRenderProcessHost()->GetID();
[email protected]07ff5fd2012-07-12 22:39:09592 SetResult(Value::CreateIntegerValue(process_id));
[email protected]350584cd2012-05-17 18:18:26593 SendResponse(true);
[email protected]8a661f82010-10-19 21:47:11594 }
[email protected]381162b2010-01-28 17:29:35595
[email protected]350584cd2012-05-17 18:18:26596 // Balance the AddRef in the RunImpl.
597 Release();
598}
599
[email protected]ef3f4f92012-10-05 03:28:29600TerminateFunction::TerminateFunction() : process_id_(-1) {
601}
602
[email protected]350584cd2012-05-17 18:18:26603bool TerminateFunction::RunImpl() {
604#if defined(ENABLE_TASK_MANAGER)
605 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &process_id_));
606
607 // Add a reference, which is balanced in TerminateProcess to keep the object
608 // around and allow for the callback to be invoked.
609 AddRef();
610
611 // If the task manager is already listening, just post a task to execute
612 // which will invoke the callback once we have returned from this function.
613 // Otherwise, wait for the notification that the task manager is done with
614 // the data gathering.
[email protected]c4dc5cc2012-11-09 08:48:39615 if (ProcessesAPI::Get(profile_)->processes_event_router()->
616 is_task_manager_listening()) {
[email protected]350584cd2012-05-17 18:18:26617 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
618 &TerminateFunction::TerminateProcess, this));
619 } else {
620 registrar_.Add(this,
621 chrome::NOTIFICATION_TASK_MANAGER_CHILD_PROCESSES_DATA_READY,
622 content::NotificationService::AllSources());
[email protected]c4dc5cc2012-11-09 08:48:39623 ProcessesAPI::Get(profile_)->processes_event_router()->
624 StartTaskManagerListening();
[email protected]350584cd2012-05-17 18:18:26625 }
626
[email protected]381162b2010-01-28 17:29:35627 return true;
[email protected]350584cd2012-05-17 18:18:26628#else
[email protected]c92dd3f2012-06-20 19:49:58629 error_ = errors::kExtensionNotSupported;
[email protected]350584cd2012-05-17 18:18:26630 return false;
631#endif // defined(ENABLE_TASK_MANAGER)
632}
633
634void TerminateFunction::Observe(
635 int type,
636 const content::NotificationSource& source,
637 const content::NotificationDetails& details) {
638 DCHECK_EQ(type, chrome::NOTIFICATION_TASK_MANAGER_CHILD_PROCESSES_DATA_READY);
639 registrar_.RemoveAll();
640 TerminateProcess();
641}
642
643void TerminateFunction::TerminateProcess() {
644 TaskManagerModel* model = TaskManager::GetInstance()->model();
645
646 int count = model->ResourceCount();
647 bool killed = false;
648 bool found = false;
649
650 for (int i = 0; i < count; ++i) {
651 if (model->IsResourceFirstInGroup(i)) {
652 if (process_id_ == model->GetUniqueChildProcessId(i)) {
653 found = true;
654 killed = base::KillProcess(model->GetProcess(i),
655 content::RESULT_CODE_KILLED, true);
656 UMA_HISTOGRAM_COUNTS("ChildProcess.KilledByExtensionAPI", 1);
657 break;
658 }
659 }
660 }
661
662 if (!found) {
[email protected]e9f541a2012-11-19 21:52:31663 error_ = ErrorUtils::FormatErrorMessage(errors::kProcessNotFound,
[email protected]350584cd2012-05-17 18:18:26664 base::IntToString(process_id_));
665 SendResponse(false);
666 } else {
[email protected]07ff5fd2012-07-12 22:39:09667 SetResult(Value::CreateBooleanValue(killed));
[email protected]350584cd2012-05-17 18:18:26668 SendResponse(true);
669 }
670
671 // Balance the AddRef in the RunImpl.
672 Release();
673}
674
[email protected]8b8e65e2012-09-14 06:47:34675GetProcessInfoFunction::GetProcessInfoFunction()
676#if defined(ENABLE_TASK_MANAGER)
677 : memory_(false)
678#endif
679 {
[email protected]350584cd2012-05-17 18:18:26680}
681
682GetProcessInfoFunction::~GetProcessInfoFunction() {
683}
684
685bool GetProcessInfoFunction::RunImpl() {
686#if defined(ENABLE_TASK_MANAGER)
687 Value* processes = NULL;
688
689 EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &processes));
690 EXTENSION_FUNCTION_VALIDATE(args_->GetBoolean(1, &memory_));
691
692 EXTENSION_FUNCTION_VALIDATE(extensions::ReadOneOrMoreIntegers(
693 processes, &process_ids_));
694
695 // Add a reference, which is balanced in GatherProcessInfo to keep the object
696 // around and allow for the callback to be invoked.
697 AddRef();
698
699 // If the task manager is already listening, just post a task to execute
700 // which will invoke the callback once we have returned from this function.
701 // Otherwise, wait for the notification that the task manager is done with
702 // the data gathering.
[email protected]c4dc5cc2012-11-09 08:48:39703 if (ProcessesAPI::Get(profile_)->processes_event_router()->
704 is_task_manager_listening()) {
[email protected]350584cd2012-05-17 18:18:26705 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
706 &GetProcessInfoFunction::GatherProcessInfo, this));
707 } else {
708 registrar_.Add(this,
709 chrome::NOTIFICATION_TASK_MANAGER_CHILD_PROCESSES_DATA_READY,
710 content::NotificationService::AllSources());
[email protected]c4dc5cc2012-11-09 08:48:39711 ProcessesAPI::Get(profile_)->processes_event_router()->
712 StartTaskManagerListening();
[email protected]350584cd2012-05-17 18:18:26713 }
714 return true;
715
716#else
[email protected]c92dd3f2012-06-20 19:49:58717 error_ = errors::kExtensionNotSupported;
[email protected]350584cd2012-05-17 18:18:26718 return false;
719#endif // defined(ENABLE_TASK_MANAGER)
720}
721
722void GetProcessInfoFunction::Observe(
723 int type,
724 const content::NotificationSource& source,
725 const content::NotificationDetails& details) {
726 DCHECK_EQ(type, chrome::NOTIFICATION_TASK_MANAGER_CHILD_PROCESSES_DATA_READY);
727 registrar_.RemoveAll();
728 GatherProcessInfo();
729}
730
731void GetProcessInfoFunction::GatherProcessInfo() {
[email protected]c92dd3f2012-06-20 19:49:58732#if defined(ENABLE_TASK_MANAGER)
[email protected]350584cd2012-05-17 18:18:26733 TaskManagerModel* model = TaskManager::GetInstance()->model();
734 DictionaryValue* processes = new DictionaryValue();
735
736 // If there are no process IDs specified, it means we need to return all of
737 // the ones we know of.
738 if (process_ids_.size() == 0) {
739 int resources = model->ResourceCount();
740 for (int i = 0; i < resources; ++i) {
741 if (model->IsResourceFirstInGroup(i)) {
742 int id = model->GetUniqueChildProcessId(i);
743 DictionaryValue* d = CreateProcessFromModel(id, model, i, false);
744 if (memory_)
745 AddMemoryDetails(d, model, i);
746 processes->Set(base::IntToString(id), d);
747 }
748 }
749 } else {
750 int resources = model->ResourceCount();
751 for (int i = 0; i < resources; ++i) {
752 if (model->IsResourceFirstInGroup(i)) {
753 int id = model->GetUniqueChildProcessId(i);
754 std::vector<int>::iterator proc_id = std::find(process_ids_.begin(),
755 process_ids_.end(), id);
756 if (proc_id != process_ids_.end()) {
757 DictionaryValue* d = CreateProcessFromModel(id, model, i, false);
758 if (memory_)
759 AddMemoryDetails(d, model, i);
760 processes->Set(base::IntToString(id), d);
761
762 process_ids_.erase(proc_id);
763 if (process_ids_.size() == 0)
764 break;
765 }
766 }
767 }
[email protected]79a60642012-10-20 21:03:18768 DCHECK_EQ(process_ids_.size(), 0U);
[email protected]350584cd2012-05-17 18:18:26769 }
770
[email protected]07ff5fd2012-07-12 22:39:09771 SetResult(processes);
[email protected]350584cd2012-05-17 18:18:26772 SendResponse(true);
773
774 // Balance the AddRef in the RunImpl.
775 Release();
[email protected]c92dd3f2012-06-20 19:49:58776#endif // defined(ENABLE_TASK_MANAGER)
[email protected]381162b2010-01-28 17:29:35777}
[email protected]bc500fa2012-09-06 09:03:30778
779} // namespace extensions