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

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

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