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

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

Powered by Google App Engine
This is Rietveld 408576698