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

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: Schema file synced with docs, some minor cleanup. 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"
15 #include "chrome/browser/extensions/extension_processes_api_constants.h" 16 #include "chrome/browser/extensions/extension_processes_api_constants.h"
17 #include "chrome/browser/extensions/extension_service.h"
16 #include "chrome/browser/extensions/extension_tab_util.h" 18 #include "chrome/browser/extensions/extension_tab_util.h"
17 #include "chrome/browser/extensions/extension_tabs_module_constants.h" 19 #include "chrome/browser/extensions/extension_tabs_module_constants.h"
18 #include "chrome/browser/profiles/profile.h" 20 #include "chrome/browser/profiles/profile.h"
19 #include "chrome/browser/task_manager/task_manager.h" 21 #include "chrome/browser/task_manager/task_manager.h"
20 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" 22 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
23 #include "chrome/common/chrome_notification_types.h"
21 #include "chrome/common/extensions/extension_error_utils.h" 24 #include "chrome/common/extensions/extension_error_utils.h"
25 #include "content/public/browser/browser_thread.h"
26 #include "content/public/browser/notification_details.h"
27 #include "content/public/browser/notification_service.h"
28 #include "content/public/browser/notification_source.h"
22 #include "content/public/browser/notification_types.h" 29 #include "content/public/browser/notification_types.h"
23 #include "content/public/browser/render_process_host.h" 30 #include "content/public/browser/render_process_host.h"
31 #include "content/public/browser/render_view_host.h"
32 #include "content/public/browser/render_view_host_delegate.h"
33 #include "content/public/browser/render_widget_host.h"
24 #include "content/public/browser/web_contents.h" 34 #include "content/public/browser/web_contents.h"
35 #include "content/public/common/result_codes.h"
25 36
26 namespace keys = extension_processes_api_constants; 37 namespace keys = extension_processes_api_constants;
27 38 namespace errors = extension_processes_api_constants;
28 DictionaryValue* CreateProcessValue(int process_id, 39
29 const std::string& type, 40 namespace {
30 double cpu, 41
31 int64 net, 42 #if defined(ENABLE_TASK_MANAGER)
32 int64 pr_mem, 43
33 int64 sh_mem) { 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
Matt Perry 2012/05/07 20:33:34 nit: end with .
nasko 2012/05/08 00:34:56 Done.
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::RenderViewHostDelegate* host_delegate = host->GetDelegate();
123 content::WebContents* contents = host_delegate->GetAsWebContents();
124 if (contents != NULL) {
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) {
34 DictionaryValue* result = new DictionaryValue(); 141 DictionaryValue* result = new DictionaryValue();
142 size_t mem;
143
35 result->SetInteger(keys::kIdKey, process_id); 144 result->SetInteger(keys::kIdKey, process_id);
36 result->SetString(keys::kTypeKey, type); 145 result->SetInteger(keys::kOsProcessIdKey, model->GetProcessId(index));
37 result->SetDouble(keys::kCpuKey, cpu); 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));
38 result->SetDouble(keys::kNetworkKey, static_cast<double>(net)); 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;
39 result->SetDouble(keys::kPrivateMemoryKey, static_cast<double>(pr_mem)); 206 result->SetDouble(keys::kPrivateMemoryKey, static_cast<double>(pr_mem));
40 result->SetDouble(keys::kSharedMemoryKey, static_cast<double>(sh_mem)); 207 }
41 return result; 208
42 } 209 #endif // defined(ENABLE_TASK_MANAGER)
210
211 } // local namespace
43 212
44 ExtensionProcessesEventRouter* ExtensionProcessesEventRouter::GetInstance() { 213 ExtensionProcessesEventRouter* ExtensionProcessesEventRouter::GetInstance() {
45 return Singleton<ExtensionProcessesEventRouter>::get(); 214 return Singleton<ExtensionProcessesEventRouter>::get();
46 } 215 }
47 216
48 ExtensionProcessesEventRouter::ExtensionProcessesEventRouter() { 217 ExtensionProcessesEventRouter::ExtensionProcessesEventRouter()
218 : listeners_(0),
219 task_manager_listening_(false) {
49 #if defined(ENABLE_TASK_MANAGER) 220 #if defined(ENABLE_TASK_MANAGER)
50 model_ = TaskManager::GetInstance()->model(); 221 model_ = TaskManager::GetInstance()->model();
51 model_->AddObserver(this); 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());
52 #endif // defined(ENABLE_TASK_MANAGER) 228 #endif // defined(ENABLE_TASK_MANAGER)
53 } 229 }
54 230
55 ExtensionProcessesEventRouter::~ExtensionProcessesEventRouter() { 231 ExtensionProcessesEventRouter::~ExtensionProcessesEventRouter() {
56 #if defined(ENABLE_TASK_MANAGER) 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
57 model_->RemoveObserver(this); 241 model_->RemoveObserver(this);
58 #endif // defined(ENABLE_TASK_MANAGER) 242 #endif // defined(ENABLE_TASK_MANAGER)
59 } 243 }
60 244
61 void ExtensionProcessesEventRouter::ObserveProfile(Profile* profile) { 245 void ExtensionProcessesEventRouter::ObserveProfile(Profile* profile) {
62 profiles_.insert(profile); 246 profiles_.insert(profile);
63 } 247 }
64 248
65 void ExtensionProcessesEventRouter::ListenerAdded() { 249 void ExtensionProcessesEventRouter::ListenerAdded() {
66 #if defined(ENABLE_TASK_MANAGER) 250 #if defined(ENABLE_TASK_MANAGER)
251 // The task manager has its own ref count to balance other callers of
252 // StartUpdating/StopUpdating.
67 model_->StartUpdating(); 253 model_->StartUpdating();
68 #endif // defined(ENABLE_TASK_MANAGER) 254 #endif // defined(ENABLE_TASK_MANAGER)
255 ++listeners_;
69 } 256 }
70 257
71 void ExtensionProcessesEventRouter::ListenerRemoved() { 258 void ExtensionProcessesEventRouter::ListenerRemoved() {
72 #if defined(ENABLE_TASK_MANAGER) 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.
73 model_->StopUpdating(); 264 model_->StopUpdating();
74 #endif // defined(ENABLE_TASK_MANAGER) 265 #endif // defined(ENABLE_TASK_MANAGER)
75 } 266 }
76 267
268 bool ExtensionProcessesEventRouter::DidStartTaskManagerListening() {
Matt Perry 2012/05/07 20:33:34 DidFoo sounds like you're notifying someone that F
nasko 2012/05/08 00:34:56 Done.
269 #if defined(ENABLE_TASK_MANAGER)
270 if (!task_manager_listening_) {
271 model_->StartListening();
272 task_manager_listening_ = true;
273 return true;
274 }
275 #endif // defined(ENABLE_TASK_MANAGER)
276 return false;
277 }
278
279 void ExtensionProcessesEventRouter::Observe(
280 int type,
281 const content::NotificationSource& source,
282 const content::NotificationDetails& details) {
283
284 switch (type) {
285 case content::NOTIFICATION_RENDERER_PROCESS_HANG:
286 ProcessHangEvent(
287 content::Source<content::RenderWidgetHost>(source).ptr());
288 break;
289 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED:
290 ProcessClosedEvent(
291 content::Source<content::RenderProcessHost>(source).ptr(),
292 content::Details<content::RenderProcessHost::RendererClosedDetails>(
293 details).ptr());
294 break;
295 default:
296 NOTREACHED() << "Unexpected observe of type " << type;
297 }
298 return;
299 }
300
301 void ExtensionProcessesEventRouter::OnItemsAdded(int start, int length) {
302 #if defined(ENABLE_TASK_MANAGER)
303 DCHECK_EQ(length, 1);
304 int index = start;
305
306 std::string event(keys::kOnCreated);
307 if (!HasEventListeners(event))
308 return;
309
310 // If the item being added is not the first one in the group, find the base
311 // index and use it for retrieving the process data.
312 if (!model_->IsResourceFirstInGroup(start)) {
313 index = model_->GetGroupIndexForResource(start);
314 }
315
316 ListValue args;
317 DictionaryValue* process = CreateProcessFromModel(
318 model_->GetUniqueChildProcessId(index), model_, index, false);
319 DCHECK(process != NULL);
320
321 if (process == NULL)
322 return;
323
324 args.Append(process);
325
326 std::string json_args;
327 base::JSONWriter::Write(&args, &json_args);
328 NotifyProfiles(keys::kOnCreated, json_args);
329 #endif // defined(ENABLE_TASK_MANAGER)
330 }
331
77 void ExtensionProcessesEventRouter::OnItemsChanged(int start, int length) { 332 void ExtensionProcessesEventRouter::OnItemsChanged(int start, int length) {
78 #if defined(ENABLE_TASK_MANAGER) 333 #if defined(ENABLE_TASK_MANAGER)
79 if (model_) { 334 // If we don't have any listeners, return immediately.
335 if (listeners_ == 0)
336 return;
337
338 if (!model_)
339 return;
340
341 // We need to know which type of onUpdated events to fire and whether to
342 // collect memory or not.
343 std::string updated_event(keys::kOnUpdated);
344 std::string updated_event_memory(keys::kOnUpdatedWithMemory);
345 bool updated = HasEventListeners(updated_event);
346 bool updated_memory = HasEventListeners(updated_event_memory);
347
348 DCHECK(updated || updated_memory);
349
350 IDMap<DictionaryValue> processes_map;
351 for (int i = start; i < start + length; i++) {
352 if (model_->IsResourceFirstInGroup(i)) {
353 int id = model_->GetUniqueChildProcessId(i);
354 DictionaryValue* process = CreateProcessFromModel(id, model_, i, true);
355 processes_map.AddWithID(process, i);
356 }
357 }
358
359 int id;
360 std::string idkey(keys::kIdKey);
361 DictionaryValue* processes = new DictionaryValue();
362
363 if (updated) {
364 IDMap<DictionaryValue>::iterator it(&processes_map);
365 for (; !it.IsAtEnd(); it.Advance()) {
366 if (!it.GetCurrentValue()->GetInteger(idkey, &id))
367 continue;
368
369 // Store each process indexed by the string version of its id.
370 processes->Set(base::IntToString(id), it.GetCurrentValue());
371 }
372
80 ListValue args; 373 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); 374 args.Append(processes);
145
146 std::string json_args; 375 std::string json_args;
147 base::JSONWriter::Write(&args, &json_args); 376 base::JSONWriter::Write(&args, &json_args);
148 377 NotifyProfiles(keys::kOnUpdated, json_args);
149 // Notify each profile that is interested. 378 }
150 for (ProfileSet::iterator it = profiles_.begin(); 379
151 it != profiles_.end(); it++) { 380 if (updated_memory) {
152 Profile* profile = *it; 381 IDMap<DictionaryValue>::iterator it(&processes_map);
153 DispatchEvent(profile, keys::kOnUpdated, json_args); 382 for (; !it.IsAtEnd(); it.Advance()) {
154 } 383 if (!it.GetCurrentValue()->GetInteger(idkey, &id))
155 } 384 continue;
156 #endif // defined(ENABLE_TASK_MANAGER) 385
157 } 386 AddMemoryDetails(it.GetCurrentValue(), model_, it.GetCurrentKey());
158 387
159 void ExtensionProcessesEventRouter::DispatchEvent(Profile* profile, 388 // Store each process indexed by the string version of its id if we didn't
389 // already insert it as part of the onUpdated processing above.
390 if (!updated)
391 processes->Set(base::IntToString(id), it.GetCurrentValue());
392 }
393
394 ListValue args;
395 args.Append(processes);
396 std::string json_args;
397 base::JSONWriter::Write(&args, &json_args);
398 NotifyProfiles(keys::kOnUpdatedWithMemory, json_args);
399 }
400 #endif // defined(ENABLE_TASK_MANAGER)
401 }
402
403 void ExtensionProcessesEventRouter::OnItemsToBeRemoved(int start, int length) {
404 #if defined(ENABLE_TASK_MANAGER)
405 DCHECK(length == 1);
406
407 // Process exit for renderer processes has the data about exit code and
408 // termination status, therefore we will rely on notifications and not on
409 // the Task Manager data. We do use the rest of this method for non-renderer
410 // processes.
411 if (model_->GetResourceType(start) == TaskManager::Resource::RENDERER)
412 return;
413
414 // The callback function parameters.
415 ListValue args;
416
417 // First arg: The id of the process that was closed.
418 args.Append(Value::CreateIntegerValue(
419 model_->GetUniqueChildProcessId(start)));
420
421 // Second arg: The exit type for the process.
422 args.Append(Value::CreateIntegerValue(0));
423
424 // Third arg: The exit code for the process.
425 args.Append(Value::CreateIntegerValue(0));
426
427 std::string json_args;
428 base::JSONWriter::Write(&args, &json_args);
429 NotifyProfiles(keys::kOnExited, json_args);
430 #endif // defined(ENABLE_TASK_MANAGER)
431 }
432
433 void ExtensionProcessesEventRouter::ProcessHangEvent(
434 content::RenderWidgetHost* widget) {
435 #if defined(ENABLE_TASK_MANAGER)
436 std::string event(keys::kOnUnresponsive);
437 if (!HasEventListeners(event))
438 return;
439
440 DictionaryValue* process = NULL;
441 int count = model_->ResourceCount();
442 int id = widget->GetProcess()->GetID();
443
444 for (int i = 0; i < count; ++i) {
445 if (model_->IsResourceFirstInGroup(i)) {
446 if (id == model_->GetUniqueChildProcessId(i)) {
447 process = CreateProcessFromModel(id, model_, i, false);
448 break;
449 }
450 }
451 }
452
453 DCHECK(process);
454 if (process == NULL)
455 return;
456
457 ListValue args;
458 args.Append(process);
459
460 std::string json_args;
461 base::JSONWriter::Write(&args, &json_args);
462 NotifyProfiles(keys::kOnUnresponsive, json_args);
463 #endif // defined(ENABLE_TASK_MANAGER)
464 }
465
466 void ExtensionProcessesEventRouter::ProcessClosedEvent(
467 content::RenderProcessHost* rph,
468 content::RenderProcessHost::RendererClosedDetails* details) {
469 #if defined(ENABLE_TASK_MANAGER)
470 // The callback function parameters.
471 ListValue args;
472
473 // First arg: The id of the process that was closed.
474 args.Append(Value::CreateIntegerValue(rph->GetID()));
475
476 // Second arg: The exit type for the process.
477 args.Append(Value::CreateIntegerValue(details->status));
478
479 // Third arg: The exit code for the process.
480 args.Append(Value::CreateIntegerValue(details->exit_code));
481
482 std::string json_args;
483 base::JSONWriter::Write(&args, &json_args);
484 NotifyProfiles(keys::kOnExited, json_args);
485 #endif // defined(ENABLE_TASK_MANAGER)
486 }
487
488 void ExtensionProcessesEventRouter::DispatchEvent(
489 Profile* profile,
160 const char* event_name, 490 const char* event_name,
161 const std::string& json_args) { 491 const std::string& json_args) {
162 if (profile && profile->GetExtensionEventRouter()) { 492 if (profile && profile->GetExtensionEventRouter()) {
163 profile->GetExtensionEventRouter()->DispatchEventToRenderers( 493 profile->GetExtensionEventRouter()->DispatchEventToRenderers(
164 event_name, json_args, NULL, GURL()); 494 event_name, json_args, NULL, GURL());
165 } 495 }
166 } 496 }
167 497
498 void ExtensionProcessesEventRouter::NotifyProfiles(const char* event_name,
499 std::string json_args) {
500 for (ProfileSet::iterator it = profiles_.begin();
501 it != profiles_.end(); it++) {
502 Profile* profile = *it;
503 DispatchEvent(profile, event_name, json_args);
504 }
505 }
506
507 // In order to determine whether there are any listeners for the event of
508 // interest, we need to ask each profile whether it has one registered.
509 // We only need to look for the profiles that have registered with the
510 // this extension API.
511 bool ExtensionProcessesEventRouter::HasEventListeners(std::string& event_name) {
512 for (ProfileSet::iterator it = profiles_.begin();
513 it != profiles_.end(); it++) {
514 Profile* profile = *it;
515 ExtensionEventRouter* router = profile->GetExtensionEventRouter();
516 if (!router)
517 continue;
518
519 if (router->HasEventListener(event_name))
520 return true;
521 }
522 return false;
523 }
524
168 bool GetProcessIdForTabFunction::RunImpl() { 525 bool GetProcessIdForTabFunction::RunImpl() {
169 int tab_id; 526 #if defined(ENABLE_TASK_MANAGER)
170 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &tab_id)); 527 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &tab_id_));
171 528
529 // Add a reference, which is balanced in GetProcessIdForTab to keep the object
530 // around and allow for the callback to be invoked.
531 AddRef();
532
533 // If the task manager is already listening, just post a task to execute
534 // which will invoke the callback once we have returned from this function.
535 // Otherwise, wait for the notification that the task manager is done with
536 // the data gathering.
537 if (ExtensionProcessesEventRouter::GetInstance()->
538 is_task_manager_listening()) {
539 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
540 &GetProcessIdForTabFunction::GetProcessIdForTab, this));
541 } else {
542 registrar_.Add(this,
543 chrome::NOTIFICATION_TASK_MANAGER_CHILD_PROCESSES_DATA_READY,
544 content::NotificationService::AllSources());
545 ExtensionProcessesEventRouter::GetInstance()->
546 DidStartTaskManagerListening();
Matt Perry 2012/05/07 20:33:34 If this returns false, the AddRef will never be ba
nasko 2012/05/08 00:34:56 Removed the return value of StartTaskManagerListen
Matt Perry 2012/05/08 01:00:34 Actually I was more worried about what would happe
547 }
548
549 return true;
550 #else
551 error_ = ExtensionErrorUtils::FormatErrorMessage(
552 errors::kExtensionNotSupported);
553 return false;
554 #endif // defined(ENABLE_TASK_MANAGER)
555 }
556
557 void GetProcessIdForTabFunction::Observe(
558 int type,
559 const content::NotificationSource& source,
560 const content::NotificationDetails& details) {
561 DCHECK_EQ(type, chrome::NOTIFICATION_TASK_MANAGER_CHILD_PROCESSES_DATA_READY);
562 registrar_.RemoveAll();
563 GetProcessIdForTab();
564 }
565
566 void GetProcessIdForTabFunction::GetProcessIdForTab() {
172 TabContentsWrapper* contents = NULL; 567 TabContentsWrapper* contents = NULL;
173 int tab_index = -1; 568 int tab_index = -1;
174 if (!ExtensionTabUtil::GetTabById(tab_id, profile(), include_incognito(), 569 if (!ExtensionTabUtil::GetTabById(tab_id_, profile(), include_incognito(),
175 NULL, NULL, &contents, &tab_index)) { 570 NULL, NULL, &contents, &tab_index)) {
176 error_ = ExtensionErrorUtils::FormatErrorMessage( 571 error_ = ExtensionErrorUtils::FormatErrorMessage(
177 extension_tabs_module_constants::kTabNotFoundError, 572 extension_tabs_module_constants::kTabNotFoundError,
178 base::IntToString(tab_id)); 573 base::IntToString(tab_id_));
179 return false; 574 result_.reset(Value::CreateIntegerValue(-1));
180 } 575 SendResponse(false);
181 576 } else {
182 // Return the process ID of the tab as an integer. 577 int process_id = contents->web_contents()->GetRenderProcessHost()->GetID();
183 int id = base::GetProcId(contents->web_contents()-> 578 result_.reset(Value::CreateIntegerValue(process_id));
184 GetRenderProcessHost()->GetHandle()); 579 SendResponse(true);
185 result_.reset(Value::CreateIntegerValue(id)); 580 }
581
582 // Balance the AddRef in the RunImpl.
583 Release();
584 }
585
586 bool TerminateFunction::RunImpl() {
587 #if defined(ENABLE_TASK_MANAGER)
588 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &process_id_));
589
590 // Add a reference, which is balanced in TerminateProcess to keep the object
591 // around and allow for the callback to be invoked.
592 AddRef();
593
594 // If the task manager is already listening, just post a task to execute
595 // which will invoke the callback once we have returned from this function.
596 // Otherwise, wait for the notification that the task manager is done with
597 // the data gathering.
598 if (ExtensionProcessesEventRouter::GetInstance()->
599 is_task_manager_listening()) {
600 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
601 &TerminateFunction::TerminateProcess, this));
602 } else {
603 registrar_.Add(this,
604 chrome::NOTIFICATION_TASK_MANAGER_CHILD_PROCESSES_DATA_READY,
605 content::NotificationService::AllSources());
606 ExtensionProcessesEventRouter::GetInstance()->
607 DidStartTaskManagerListening();
608 }
609
186 return true; 610 return true;
187 } 611 #else
612 error_ = ExtensionErrorUtils::FormatErrorMessage(
613 errors::kExtensionNotSupported);
614 return false;
615 #endif // defined(ENABLE_TASK_MANAGER)
616 }
617
618 void TerminateFunction::Observe(
619 int type,
620 const content::NotificationSource& source,
621 const content::NotificationDetails& details) {
622 DCHECK_EQ(type, chrome::NOTIFICATION_TASK_MANAGER_CHILD_PROCESSES_DATA_READY);
623 registrar_.RemoveAll();
624 TerminateProcess();
625 }
626
627 void TerminateFunction::TerminateProcess() {
628 TaskManagerModel* model = TaskManager::GetInstance()->model();
629
630 int count = model->ResourceCount();
631 bool killed = false;
632 bool found = false;
633
634 for (int i = 0; i < count; ++i) {
635 if (model->IsResourceFirstInGroup(i)) {
636 if (process_id_ == model->GetUniqueChildProcessId(i)) {
637 found = true;
638 killed = base::KillProcess(model->GetProcess(i),
639 content::RESULT_CODE_KILLED, true);
640 UMA_HISTOGRAM_COUNTS("ChildProcess.KilledByExtensionAPI", 1);
641 break;
642 }
643 }
644 }
645
646 if (!found) {
647 error_ = ExtensionErrorUtils::FormatErrorMessage(errors::kProcessNotFound,
648 base::IntToString(process_id_));
649 SendResponse(false);
650 } else {
651 result_.reset(Value::CreateBooleanValue(killed));
652 SendResponse(true);
653 }
654
655 // Balance the AddRef in the RunImpl.
656 Release();
657 }
658
659 GetProcessInfoFunction::GetProcessInfoFunction() {
660 }
661
662 GetProcessInfoFunction::~GetProcessInfoFunction() {
663 }
664
665 bool GetProcessInfoFunction::RunImpl() {
666 #if defined(ENABLE_TASK_MANAGER)
667 Value* processes = NULL;
668
669 EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &processes));
670 EXTENSION_FUNCTION_VALIDATE(args_->GetBoolean(1, &memory_));
671
672 EXTENSION_FUNCTION_VALIDATE(ExtensionTabUtil::ReadOneOrMoreIntegers(
673 processes, &process_ids_));
674
675 // Add a reference, which is balanced in GatherProcessInfo to keep the object
676 // around and allow for the callback to be invoked.
677 AddRef();
678
679 // If the task manager is already listening, just post a task to execute
680 // which will invoke the callback once we have returned from this function.
681 // Otherwise, wait for the notification that the task manager is done with
682 // the data gathering.
683 if (ExtensionProcessesEventRouter::GetInstance()->
684 is_task_manager_listening()) {
685 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
686 &GetProcessInfoFunction::GatherProcessInfo, this));
687 } else {
688 registrar_.Add(this,
689 chrome::NOTIFICATION_TASK_MANAGER_CHILD_PROCESSES_DATA_READY,
690 content::NotificationService::AllSources());
691 ExtensionProcessesEventRouter::GetInstance()->
692 DidStartTaskManagerListening();
693 }
694 return true;
695
696 #else
697 error_ = ExtensionErrorUtils::FormatErrorMessage(
698 errors::kExtensionNotSupported);
699 return false;
700 #endif // defined(ENABLE_TASK_MANAGER)
701 }
702
703 void GetProcessInfoFunction::Observe(
704 int type,
705 const content::NotificationSource& source,
706 const content::NotificationDetails& details) {
707 DCHECK_EQ(type, chrome::NOTIFICATION_TASK_MANAGER_CHILD_PROCESSES_DATA_READY);
708 registrar_.RemoveAll();
709 GatherProcessInfo();
710 }
711
712 void GetProcessInfoFunction::GatherProcessInfo() {
713 TaskManagerModel* model = TaskManager::GetInstance()->model();
714 DictionaryValue* processes = new DictionaryValue();
715
716 // If there are no process IDs specified, it means we need to return all of
717 // the ones we know of.
718 if (process_ids_.size() == 0) {
719 int resources = model->ResourceCount();
720 for (int i = 0; i < resources; ++i) {
721 if (model->IsResourceFirstInGroup(i)) {
722 int id = model->GetUniqueChildProcessId(i);
723 DictionaryValue* d = CreateProcessFromModel(id, model, i, false);
724 if (memory_)
725 AddMemoryDetails(d, model, i);
726 processes->Set(base::IntToString(id), d);
727 }
728 }
729 } else {
730 int resources = model->ResourceCount();
731 for (int i = 0; i < resources; ++i) {
732 if (model->IsResourceFirstInGroup(i)) {
733 int id = model->GetUniqueChildProcessId(i);
734 std::vector<int>::iterator proc_id = std::find(process_ids_.begin(),
735 process_ids_.end(), id);
736 if (proc_id != process_ids_.end()) {
737 DictionaryValue* d = CreateProcessFromModel(id, model, i, false);
738 if (memory_)
739 AddMemoryDetails(d, model, i);
740 processes->Set(base::IntToString(id), d);
741
742 process_ids_.erase(proc_id);
743 if (process_ids_.size() == 0)
744 break;
745 }
746 }
747 }
748 DCHECK(process_ids_.size() == 0);
749 }
750
751 result_.reset(processes);
752 SendResponse(true);
753
754 // Balance the AddRef in the RunImpl.
755 Release();
756 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698