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

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

Powered by Google App Engine
This is Rietveld 408576698