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

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: Created 8 years, 8 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"
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_widget_host.h"
24 #include "content/public/browser/web_contents.h" 31 #include "content/public/browser/web_contents.h"
32 #include "content/public/common/result_codes.h"
25 33
26 namespace keys = extension_processes_api_constants; 34 namespace keys = extension_processes_api_constants;
35 namespace errors = extension_processes_api_constants;
27 36
28 DictionaryValue* CreateProcessValue(int process_id, 37 DictionaryValue* CreateCacheData(
29 const std::string& type, 38 const WebKit::WebCache::ResourceTypeStat& stat) {
30 double cpu, 39
31 int64 net, 40 DictionaryValue* cache = new DictionaryValue();
32 int64 pr_mem, 41 cache->SetDouble(keys::kCacheSize, static_cast<double>(stat.size));
33 int64 sh_mem) { 42 cache->SetDouble(keys::kCacheLiveSize, static_cast<double>(stat.liveSize));
43 return cache;
44 }
45
46 void SetProcessType(DictionaryValue* result,
47 TaskManagerModel* model,
48 int index) {
49 // Determine process type
50 std::string type = keys::kProcessTypeOther;
51 TaskManager::Resource::Type resource_type = model->GetResourceType(index);
52 switch (resource_type) {
53 case TaskManager::Resource::BROWSER:
54 type = keys::kProcessTypeBrowser;
55 break;
56 case TaskManager::Resource::RENDERER:
57 type = keys::kProcessTypeRenderer;
58 break;
59 case TaskManager::Resource::EXTENSION:
60 type = keys::kProcessTypeExtension;
61 break;
62 case TaskManager::Resource::NOTIFICATION:
63 type = keys::kProcessTypeNotification;
64 break;
65 case TaskManager::Resource::PLUGIN:
66 type = keys::kProcessTypePlugin;
67 break;
68 case TaskManager::Resource::WORKER:
69 type = keys::kProcessTypeWorker;
70 break;
71 case TaskManager::Resource::NACL:
72 type = keys::kProcessTypeNacl;
73 break;
74 case TaskManager::Resource::UTILITY:
75 type = keys::kProcessTypeUtility;
76 break;
77 case TaskManager::Resource::GPU:
78 type = keys::kProcessTypeGPU;
79 break;
80 case TaskManager::Resource::PROFILE_IMPORT:
81 case TaskManager::Resource::ZYGOTE:
82 case TaskManager::Resource::SANDBOX_HELPER:
83 case TaskManager::Resource::UNKNOWN:
84 type = keys::kProcessTypeOther;
85 break;
86 default:
87 NOTREACHED() << "Unknown resource type.";
88 }
89 result->SetString(keys::kTypeKey, type);
90 }
91
92 DictionaryValue* CreateProcessFromModel(int process_id,
93 TaskManagerModel* model,
94 int index) {
34 DictionaryValue* result = new DictionaryValue(); 95 DictionaryValue* result = new DictionaryValue();
96 size_t mem;
97
35 result->SetInteger(keys::kIdKey, process_id); 98 result->SetInteger(keys::kIdKey, process_id);
36 result->SetString(keys::kTypeKey, type); 99 result->SetInteger(keys::kOsProcessId, model->GetProcessId(index));
37 result->SetDouble(keys::kCpuKey, cpu); 100 SetProcessType(result, model, index);
101 result->SetString(keys::kProfile,
102 model->GetResourceProfileName(index));
103 result->SetDouble(keys::kCpuKey, model->GetCPUUsage(index));
104
105 if (model->GetV8Memory(index, &mem))
106 result->SetDouble(keys::kJsMemoryAllocated,
107 static_cast<double>(mem));
108
109 if (model->GetV8MemoryUsed(index, &mem))
110 result->SetDouble(keys::kJsMemoryUsed,
111 static_cast<double>(mem));
112
113 if (model->GetSqliteMemoryUsedBytes(index, &mem))
114 result->SetDouble(keys::kSqliteMemory,
115 static_cast<double>(mem));
116
117 WebKit::WebCache::ResourceTypeStats cache_stats;
118 if (model->GetWebCoreCacheStats(index, &cache_stats)) {
119 result->Set(keys::kImageCache,
120 CreateCacheData(cache_stats.images));
Charlie Reis 2012/04/23 22:19:51 nit: Should line up with open paren.
nasko 2012/04/24 18:14:29 Done.
121 result->Set(keys::kScriptCache,
122 CreateCacheData(cache_stats.scripts));
123 result->Set(keys::kCssCache,
124 CreateCacheData(cache_stats.cssStyleSheets));
125 }
126
127 // Network and FPS are reported by the TaskManager per resource (tab), not
128 // per process, therefore we need to iterate through the group of resources
129 // and aggregate the data.
130 float fps = 0, tmp = 0;
131 int64 net = 0;
132 int length = model->GetGroupRangeForResource(index).second;
133 for (int i = 0; i < length; ++i) {
134 net += model->GetNetworkUsage(index + i);
135 if (model->GetFPS(index + i, &tmp))
136 fps += tmp;
137 }
138 result->SetDouble(keys::kFPS, static_cast<double>(fps));
38 result->SetDouble(keys::kNetworkKey, static_cast<double>(net)); 139 result->SetDouble(keys::kNetworkKey, static_cast<double>(net));
140
141 return result;
142 }
143
144 // Since memory details are expensive to gather, we don't do it by default.
145 // This function is a helper to add memory details data to an existing
146 // Process object representation.
147 void AddMemoryDetails(DictionaryValue* result,
148 TaskManagerModel* model,
149 int index) {
150 size_t mem;
151 int64 pr_mem = model->GetPrivateMemory(index, &mem) ?
152 static_cast<int64>(mem) : -1;
39 result->SetDouble(keys::kPrivateMemoryKey, static_cast<double>(pr_mem)); 153 result->SetDouble(keys::kPrivateMemoryKey, static_cast<double>(pr_mem));
40 result->SetDouble(keys::kSharedMemoryKey, static_cast<double>(sh_mem));
41 return result;
42 } 154 }
43 155
44 ExtensionProcessesEventRouter* ExtensionProcessesEventRouter::GetInstance() { 156 ExtensionProcessesEventRouter* ExtensionProcessesEventRouter::GetInstance() {
45 return Singleton<ExtensionProcessesEventRouter>::get(); 157 return Singleton<ExtensionProcessesEventRouter>::get();
46 } 158 }
47 159
48 ExtensionProcessesEventRouter::ExtensionProcessesEventRouter() { 160 ExtensionProcessesEventRouter::ExtensionProcessesEventRouter() : listeners_(0) {
49 model_ = TaskManager::GetInstance()->model(); 161 model_ = TaskManager::GetInstance()->model();
50 model_->AddObserver(this); 162 model_->AddObserver(this);
163 model_->StartUpdating();
Charlie Reis 2012/04/23 22:19:51 Why is this needed without any listeners?
nasko 2012/04/24 18:14:29 The reason is that we can return CPU/Network stats
164
165 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_HANG,
166 content::NotificationService::AllSources());
167 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
168 content::NotificationService::AllSources());
51 } 169 }
52 170
53 ExtensionProcessesEventRouter::~ExtensionProcessesEventRouter() { 171 ExtensionProcessesEventRouter::~ExtensionProcessesEventRouter() {
172 registrar_.Remove(this, content::NOTIFICATION_RENDERER_PROCESS_HANG,
173 content::NotificationService::AllSources());
174 registrar_.Remove(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
175 content::NotificationService::AllSources());
176
177 model_->StopUpdating();
54 model_->RemoveObserver(this); 178 model_->RemoveObserver(this);
55 } 179 }
56 180
57 void ExtensionProcessesEventRouter::ObserveProfile(Profile* profile) { 181 void ExtensionProcessesEventRouter::ObserveProfile(Profile* profile) {
58 profiles_.insert(profile); 182 profiles_.insert(profile);
59 } 183 }
60 184
185 void ExtensionProcessesEventRouter::Observe(
186 int type,
187 const content::NotificationSource& source,
188 const content::NotificationDetails& details) {
189
190 switch (type) {
191 case content::NOTIFICATION_RENDERER_PROCESS_HANG:
192 ProcessHangEvent(
193 content::Source<content::RenderWidgetHost>(source).ptr());
194 break;
195 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED:
196 ProcessClosedEvent(
197 content::Source<content::RenderProcessHost>(source).ptr(),
198 content::Details<content::RenderProcessHost::RendererClosedDetails>(
199 details).ptr());
200 break;
201 default:
202 NOTREACHED() << "Unexpected observe of type " << type;
203 }
204 return;
205 }
206
207 bool ExtensionProcessesEventRouter::HasEventListeners(std::string& event_name) {
Charlie Reis 2012/04/23 22:19:51 There's a fair amount going on here. Maybe add a
nasko 2012/04/24 18:14:29 Added a comment and filed crbug.com/124804 to get
208 for (ProfileSet::iterator it = profiles_.begin();
209 it != profiles_.end(); it++) {
210 Profile* profile = *it;
211 ExtensionEventRouter* router = profile->GetExtensionEventRouter();
212 if (!router || !router->HasEventListener(event_name))
213 continue;
214
215 const ExtensionService* extension_service = profile->GetExtensionService();
216 const ExtensionSet* extensions = extension_service->extensions();
217 for (ExtensionSet::const_iterator it = extensions->begin();
Charlie Reis 2012/04/23 22:19:51 FYI, this may be changing soon, so be aware of pot
nasko 2012/04/24 18:14:29 Done.
218 it != extensions->end(); ++it) {
219 std::string extension_id = (*it)->id();
220 if (router->ExtensionHasEventListener(extension_id, event_name))
221 return true;
222 }
223 }
224 return false;
225 }
226
61 void ExtensionProcessesEventRouter::ListenerAdded() { 227 void ExtensionProcessesEventRouter::ListenerAdded() {
62 model_->StartUpdating(); 228 ++listeners_;
63 } 229 }
64 230
65 void ExtensionProcessesEventRouter::ListenerRemoved() { 231 void ExtensionProcessesEventRouter::ListenerRemoved() {
66 model_->StopUpdating(); 232 DCHECK(listeners_ > 0);
233 --listeners_;
234 }
235
236 void ExtensionProcessesEventRouter::OnItemsAdded(int start, int length) {
237 DCHECK(length == 1);
238 int index = start;
239
240 std::string event(keys::kOnCreated);
241 if (!HasEventListeners(event))
242 return;
243
244 // If the item being added is not the first one in the group, find the base
245 // index and use it for retrieving the process data.
246 if (!model_->IsResourceFirstInGroup(start)) {
247 index = model_->GetGroupIndexForResource(start);
248 }
249
250 ListValue args;
251 DictionaryValue* process = CreateProcessFromModel(
252 model_->GetUniqueChildProcessId(index), model_, index);
253 DCHECK(process != NULL);
254
255 if (process == NULL)
256 return;
257
258 args.Append(Value::CreateIntegerValue(
259 model_->GetUniqueChildProcessId(start)));
260 args.Append(process);
261
262 std::string json_args;
263 base::JSONWriter::Write(&args, &json_args);
264 NotifyProfiles(keys::kOnCreated, json_args);
265 }
266
267 void ExtensionProcessesEventRouter::OnItemsToBeRemoved(int start, int length) {
268 DCHECK(length == 1);
269
270 // Process exit for renderer processes has the data about exit code and
271 // termination status, therefore we will rely on notifications and not on
272 // the Task Manager data.
Charlie Reis 2012/04/23 22:19:51 But we do use the Task Manager's ToBeRemoved for n
nasko 2012/04/24 18:14:29 Done.
273 if (model_->GetResourceType(start) == TaskManager::Resource::RENDERER)
274 return;
275
276 // The callback function parameters.
277 ListValue args;
278
279 // First arg: The id of the process that was closed.
280 args.Append(Value::CreateIntegerValue(
281 model_->GetUniqueChildProcessId(start)));
282
283 // Second arg: The exit type for the process.
284 args.Append(Value::CreateIntegerValue(0));
285
286 // Third arg: The exit code for the process.
Charlie Reis 2012/04/23 22:19:51 Thanks for documenting these. Is it not possible
nasko 2012/04/24 18:14:29 It is just a simplification, since we don't have t
287 args.Append(Value::CreateIntegerValue(0));
288
289 std::string json_args;
290 base::JSONWriter::Write(&args, &json_args);
291 NotifyProfiles(keys::kOnExited, json_args);
67 } 292 }
68 293
69 void ExtensionProcessesEventRouter::OnItemsChanged(int start, int length) { 294 void ExtensionProcessesEventRouter::OnItemsChanged(int start, int length) {
70 if (model_) { 295 // If we don't have any listeners, return immediately.
296 if (listeners_ == 0)
297 return;
298
299 if (!model_)
300 return;
301
302 // We need to know which type of onUpdated events to fire and whether to
303 // collect memory or not.
304 std::string updated_event(keys::kOnUpdated);
305 std::string updated_event_memory(keys::kOnUpdatedWithMemory);
306 bool updated = HasEventListeners(updated_event);
307 bool updated_memory = HasEventListeners(updated_event_memory);
308
309 DCHECK(updated || updated_memory);
310
311 IDMap<DictionaryValue> processes_map;
312 for (int i = start; i < start + length; i++) {
313 if (model_->IsResourceFirstInGroup(i)) {
314 int id = model_->GetUniqueChildProcessId(i);
315 DictionaryValue* process = CreateProcessFromModel(id, model_, i);
316 processes_map.AddWithID(process, i);
317 }
318 }
319
320 int id;
321 std::string idkey(keys::kIdKey);
322 DictionaryValue* processes = new DictionaryValue();
323
324 if (updated) {
325 IDMap<DictionaryValue>::iterator it(&processes_map);
326 for (; !it.IsAtEnd(); it.Advance()) {
327 if (!it.GetCurrentValue()->GetInteger(idkey, &id))
328 continue;
329
330 // Store each process indexed by the string version of its id
Charlie Reis 2012/04/23 22:19:51 nit: End with period, here and below. (Yep, proba
nasko 2012/04/24 18:14:29 Done.
331 processes->Set(base::IntToString(id), it.GetCurrentValue());
332 }
333
71 ListValue args; 334 ListValue args;
72 DictionaryValue* processes = new DictionaryValue();
73 for (int i = start; i < start + length; i++) {
74 if (model_->IsResourceFirstInGroup(i)) {
75 int id = model_->GetProcessId(i);
76
77 // Determine process type
78 std::string type = keys::kProcessTypeOther;
79 TaskManager::Resource::Type resource_type = model_->GetResourceType(i);
80 switch (resource_type) {
81 case TaskManager::Resource::BROWSER:
82 type = keys::kProcessTypeBrowser;
83 break;
84 case TaskManager::Resource::RENDERER:
85 type = keys::kProcessTypeRenderer;
86 break;
87 case TaskManager::Resource::EXTENSION:
88 type = keys::kProcessTypeExtension;
89 break;
90 case TaskManager::Resource::NOTIFICATION:
91 type = keys::kProcessTypeNotification;
92 break;
93 case TaskManager::Resource::PLUGIN:
94 type = keys::kProcessTypePlugin;
95 break;
96 case TaskManager::Resource::WORKER:
97 type = keys::kProcessTypeWorker;
98 break;
99 case TaskManager::Resource::NACL:
100 type = keys::kProcessTypeNacl;
101 break;
102 case TaskManager::Resource::UTILITY:
103 type = keys::kProcessTypeUtility;
104 break;
105 case TaskManager::Resource::GPU:
106 type = keys::kProcessTypeGPU;
107 break;
108 case TaskManager::Resource::PROFILE_IMPORT:
109 case TaskManager::Resource::ZYGOTE:
110 case TaskManager::Resource::SANDBOX_HELPER:
111 case TaskManager::Resource::UNKNOWN:
112 type = keys::kProcessTypeOther;
113 break;
114 default:
115 NOTREACHED() << "Unknown resource type.";
116 }
117
118 // Get process metrics as numbers
119 double cpu = model_->GetCPUUsage(i);
120
121 // TODO(creis): Network is actually reported per-resource (tab),
122 // not per-process. We should aggregate it here.
123 int64 net = model_->GetNetworkUsage(i);
124 size_t mem;
125 int64 pr_mem = model_->GetPrivateMemory(i, &mem) ?
126 static_cast<int64>(mem) : -1;
127 int64 sh_mem = model_->GetSharedMemory(i, &mem) ?
128 static_cast<int64>(mem) : -1;
129
130 // Store each process indexed by the string version of its id
131 processes->Set(base::IntToString(id),
132 CreateProcessValue(id, type, cpu, net, pr_mem, sh_mem));
133 }
134 }
135 args.Append(processes); 335 args.Append(processes);
136
137 std::string json_args; 336 std::string json_args;
138 base::JSONWriter::Write(&args, &json_args); 337 base::JSONWriter::Write(&args, &json_args);
139 338 NotifyProfiles(keys::kOnUpdated, json_args);
140 // Notify each profile that is interested. 339 }
141 for (ProfileSet::iterator it = profiles_.begin(); 340
142 it != profiles_.end(); it++) { 341 if (updated_memory) {
143 Profile* profile = *it; 342 IDMap<DictionaryValue>::iterator it(&processes_map);
144 DispatchEvent(profile, keys::kOnUpdated, json_args); 343 for (; !it.IsAtEnd(); it.Advance()) {
145 } 344 if (!it.GetCurrentValue()->GetInteger(idkey, &id))
146 } 345 continue;
147 } 346
148 347 AddMemoryDetails(it.GetCurrentValue(), model_, it.GetCurrentKey());
Charlie Reis 2012/04/23 22:19:51 Hmm. I was thinking we could combine the two loop
nasko 2012/04/24 18:14:29 As we discussed verbally, the goal is to keep the
149 void ExtensionProcessesEventRouter::DispatchEvent(Profile* profile, 348 // Store each process indexed by the string version of its id
349 processes->Set(base::IntToString(id), it.GetCurrentValue());
350 }
351
352 ListValue args;
353 args.Append(processes);
354 std::string json_args;
355 base::JSONWriter::Write(&args, &json_args);
356 NotifyProfiles(keys::kOnUpdatedWithMemory, json_args);
357 }
358 }
359
360 void ExtensionProcessesEventRouter::ProcessHangEvent(
Charlie Reis 2012/04/23 22:19:51 Should we skip this if no one is listening, like O
nasko 2012/04/24 18:14:29 Good catch!
361 content::RenderWidgetHost* widget) {
362 DictionaryValue* process = NULL;
363
364 int count = model_->ResourceCount();
365 int id = widget->GetProcess()->GetID();
366
367 for (int i = 0; i < count; ++i) {
368 if (model_->IsResourceFirstInGroup(i)) {
369 if (id == model_->GetUniqueChildProcessId(i)) {
370 process = CreateProcessFromModel(id, model_, i);
371 break;
372 }
373 }
374 }
375
376 DCHECK(process != NULL);
377 if (process == NULL)
378 return;
379
380 ListValue args;
381 args.Append(process);
382
383 std::string json_args;
384 base::JSONWriter::Write(&args, &json_args);
385 NotifyProfiles(keys::kOnUnresponsive, json_args);
386 }
387
388 void ExtensionProcessesEventRouter::ProcessClosedEvent(
389 content::RenderProcessHost* rph,
390 content::RenderProcessHost::RendererClosedDetails* details) {
391 // The callback function parameters.
392 ListValue args;
393
394 // First arg: The id of the process that was closed.
395 args.Append(Value::CreateIntegerValue(rph->GetID()));
396
397 // Second arg: The exit type for the process.
398 args.Append(Value::CreateIntegerValue(details->status));
399
400 // Third arg: The exit code for the process.
401 args.Append(Value::CreateIntegerValue(details->exit_code));
402
403 std::string json_args;
404 base::JSONWriter::Write(&args, &json_args);
405 NotifyProfiles(keys::kOnExited, json_args);
406 }
407
408 void ExtensionProcessesEventRouter::DispatchEvent(
409 Profile* profile,
150 const char* event_name, 410 const char* event_name,
151 const std::string& json_args) { 411 const std::string& json_args) {
152 if (profile && profile->GetExtensionEventRouter()) { 412 if (profile && profile->GetExtensionEventRouter()) {
153 profile->GetExtensionEventRouter()->DispatchEventToRenderers( 413 profile->GetExtensionEventRouter()->DispatchEventToRenderers(
154 event_name, json_args, NULL, GURL()); 414 event_name, json_args, NULL, GURL());
155 } 415 }
156 } 416 }
157 417
418 void ExtensionProcessesEventRouter::NotifyProfiles(const char* event_name,
419 std::string json_args) {
420 for (ProfileSet::iterator it = profiles_.begin();
421 it != profiles_.end(); it++) {
422 Profile* profile = *it;
423 DispatchEvent(profile, event_name, json_args);
424 }
425 }
426
158 bool GetProcessIdForTabFunction::RunImpl() { 427 bool GetProcessIdForTabFunction::RunImpl() {
159 int tab_id; 428 int tab_id;
160 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &tab_id)); 429 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &tab_id));
161 430
162 TabContentsWrapper* contents = NULL; 431 TabContentsWrapper* contents = NULL;
163 int tab_index = -1; 432 int tab_index = -1;
164 if (!ExtensionTabUtil::GetTabById(tab_id, profile(), include_incognito(), 433 if (!ExtensionTabUtil::GetTabById(tab_id, profile(), include_incognito(),
165 NULL, NULL, &contents, &tab_index)) { 434 NULL, NULL, &contents, &tab_index)) {
166 error_ = ExtensionErrorUtils::FormatErrorMessage( 435 error_ = ExtensionErrorUtils::FormatErrorMessage(
167 extension_tabs_module_constants::kTabNotFoundError, 436 extension_tabs_module_constants::kTabNotFoundError,
168 base::IntToString(tab_id)); 437 base::IntToString(tab_id));
169 return false; 438 return false;
170 } 439 }
171 440
172 // Return the process ID of the tab as an integer. 441 int process_id = base::GetProcId(
173 int id = base::GetProcId(contents->web_contents()-> 442 contents->web_contents()->GetRenderProcessHost()->GetHandle());
174 GetRenderProcessHost()->GetHandle()); 443
175 result_.reset(Value::CreateIntegerValue(id)); 444 TaskManagerModel* model = TaskManager::GetInstance()->model();
445 int count = model->ResourceCount();
446
447 for (int i = 0; i < count; ++i) {
448 if (model->IsResourceFirstInGroup(i)) {
449 if (process_id == model->GetProcessId(i)) {
450 // Return the unique ID of the process as an integer.
451 result_.reset(Value::CreateIntegerValue(
452 model->GetUniqueChildProcessId(i)));
453 return true;
454 }
455 }
456 }
457
458 error_ = ExtensionErrorUtils::FormatErrorMessage(errors::kProcessNotFound,
459 base::IntToString(process_id));
460 return false;
461 }
462
463
464 bool TerminateFunction::RunImpl() {
465 int process_id;
466 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &process_id));
467
468 // Since we use the RenderProcessHost unique IDs to give to extensions, it is
469 // safe to just search for the corresponding RPH and kill its process.
470 // This will ensure we are not killing random non-Chrome processes.
471 content::RenderProcessHost* rph = content::RenderProcessHost::FromID(
472 process_id);
473 if (rph == NULL) {
474 error_ = ExtensionErrorUtils::FormatErrorMessage(errors::kProcessNotFound,
475 base::IntToString(process_id));
476 return false;
477 }
478
479 bool killed = false;
480 killed = base::KillProcess(rph->GetHandle(),
481 content::RESULT_CODE_KILLED,
482 true);
Charlie Reis 2012/04/23 22:19:51 Given our recent experiences, I wonder if we want
nasko 2012/04/24 18:14:29 This is a good idea. I would suggest we add it in
Charlie Reis 2012/04/27 22:01:55 I found out that the timing of the histogram CL do
483
484 result_.reset(Value::CreateBooleanValue(killed));
176 return true; 485 return true;
177 } 486 }
487
488 // Borrowed from the tabs extension. Allows us to support both list and single
489 // integer parameters as input from extensions.
Charlie Reis 2012/04/23 22:19:51 Sounds useful. Is there any shared place we can p
nasko 2012/04/24 18:14:29 Not quite sure. I will look around to see if there
Charlie Reis 2012/04/27 22:01:55 extension_tab_util.h, perhaps?
490 bool ReadOneOrMoreIntegers(Value* value, std::vector<int>* result) {
491 if (value->IsType(Value::TYPE_INTEGER)) {
492 int id = -1;
493 if (!value->GetAsInteger(&id))
494 return false;
495 result->push_back(id);
496 return true;
497 } else if (value->IsType(Value::TYPE_LIST)) {
498 ListValue* ids = static_cast<ListValue*>(value);
499 for (size_t i = 0; i < ids->GetSize(); ++i) {
500 int id = -1;
501 if (!ids->GetInteger(i, &id))
502 return false;
503 result->push_back(id);
504 }
505 return true;
506 }
507 return false;
508 }
509
510 bool GetProcessInfoFunction::RunImpl() {
511 Value* args = NULL;
512 bool memory = false;
513
514 EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &args));
515 EXTENSION_FUNCTION_VALIDATE(args_->GetBoolean(1, &memory));
516
517 std::vector<int> process_ids;
518 EXTENSION_FUNCTION_VALIDATE(ReadOneOrMoreIntegers(args, &process_ids));
519
520 TaskManagerModel* model = TaskManager::GetInstance()->model();
521 DictionaryValue* processes = new DictionaryValue();
522
523 // If there are no process IDs specified, it means we need to return all of
524 // the ones we know of.
525 if (process_ids.size() == 0) {
526 int resources = model->ResourceCount();
527 for (int i = 0; i < resources; ++i) {
528 if (model->IsResourceFirstInGroup(i)) {
529 int id = model->GetUniqueChildProcessId(i);
530 DictionaryValue* d = CreateProcessFromModel(id, model, i);
531 if (memory)
532 AddMemoryDetails(d, model, i);
533 processes->Set(base::IntToString(id), d);
534 }
535 }
536 } else {
537 int resources = model->ResourceCount();
538 for (int i = 0; i < resources; ++i) {
539 if (model->IsResourceFirstInGroup(i)) {
540 int id = model->GetUniqueChildProcessId(i);
541 std::vector<int>::iterator proc_id = std::find(process_ids.begin(),
542 process_ids.end(), id);
543 if (proc_id != process_ids.end()) {
544 DictionaryValue* d = CreateProcessFromModel(id, model, i);
545 if (memory)
546 AddMemoryDetails(d, model, i);
547 processes->Set(base::IntToString(id), d);
548
549 process_ids.erase(proc_id);
550 if (process_ids.size() == 0)
551 break;
552 }
553 }
554 }
555 DCHECK(process_ids.size() == 0);
556 }
557
558 result_.reset(processes);
559 return true;
560 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698