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

Side by Side Diff: chrome/browser/extensions/api/processes/processes_api.cc

Issue 1584473004: Migrate ProcessesEventRouter to the new task manager (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase ... Created 4 years, 9 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
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/api/processes/processes_api.h" 5 #include "chrome/browser/extensions/api/processes/processes_api.h"
6 6
7 #include <stddef.h>
8 #include <stdint.h> 7 #include <stdint.h>
9 8
10 #include <algorithm> 9 #include <algorithm>
11 #include <utility> 10
12
13 #include "base/callback.h"
14 #include "base/json/json_writer.h"
15 #include "base/lazy_instance.h" 11 #include "base/lazy_instance.h"
16 #include "base/location.h" 12 #include "base/metrics/histogram_macros.h"
17 #include "base/metrics/histogram.h" 13 #include "base/process/process.h"
18 #include "base/single_thread_task_runner.h"
19 #include "base/strings/string_number_conversions.h" 14 #include "base/strings/string_number_conversions.h"
20 #include "base/strings/utf_string_conversions.h" 15 #include "base/strings/utf_string_conversions.h"
21 #include "base/thread_task_runner_handle.h"
22 #include "base/values.h"
23 #include "chrome/browser/chrome_notification_types.h"
24 #include "chrome/browser/extensions/api/tabs/tabs_constants.h" 16 #include "chrome/browser/extensions/api/tabs/tabs_constants.h"
25 #include "chrome/browser/extensions/extension_service.h"
26 #include "chrome/browser/extensions/extension_tab_util.h" 17 #include "chrome/browser/extensions/extension_tab_util.h"
27 #include "chrome/browser/profiles/profile.h" 18 #include "chrome/browser/profiles/profile.h"
28 #include "chrome/browser/task_manager/resource_provider.h" 19 #include "chrome/browser/task_management/task_manager_interface.h"
29 #include "chrome/browser/task_manager/task_manager.h"
30 #include "chrome/common/extensions/api/processes.h" 20 #include "chrome/common/extensions/api/processes.h"
31 #include "content/public/browser/browser_context.h" 21 #include "content/public/browser/browser_child_process_host.h"
32 #include "content/public/browser/notification_details.h" 22 #include "content/public/browser/child_process_data.h"
33 #include "content/public/browser/notification_service.h" 23
34 #include "content/public/browser/notification_source.h"
35 #include "content/public/browser/notification_types.h"
36 #include "content/public/browser/render_process_host.h" 24 #include "content/public/browser/render_process_host.h"
37 #include "content/public/browser/render_view_host.h"
38 #include "content/public/browser/render_widget_host.h"
39 #include "content/public/browser/render_widget_host_iterator.h"
40 #include "content/public/browser/web_contents.h" 25 #include "content/public/browser/web_contents.h"
26 #include "content/public/common/child_process_host.h"
41 #include "content/public/common/result_codes.h" 27 #include "content/public/common/result_codes.h"
42 #include "extensions/browser/event_router.h"
43 #include "extensions/browser/extension_function_registry.h"
44 #include "extensions/browser/extension_function_util.h"
45 #include "extensions/common/error_utils.h" 28 #include "extensions/common/error_utils.h"
29 #include "third_party/WebKit/public/web/WebCache.h"
46 30
47 namespace extensions { 31 namespace extensions {
48 32
49 namespace errors { 33 namespace errors {
50 const char kNotAllowedToTerminate[] = "Not allowed to terminate process: *."; 34 const char kNotAllowedToTerminate[] = "Not allowed to terminate process: *.";
51 const char kProcessNotFound[] = "Process not found: *."; 35 const char kProcessNotFound[] = "Process not found: *.";
52 const char kInavlidArgument[] = "Invalid argument: *."; 36 const char kInvalidArgument[] = "Invalid argument: *.";
53 } // namespace errors 37 } // namespace errors
54 38
55 namespace { 39 namespace {
56 40
57 #if defined(ENABLE_TASK_MANAGER) 41 base::LazyInstance<BrowserContextKeyedAPIFactory<ProcessesAPI> >
42 g_processes_api_factory = LAZY_INSTANCE_INITIALIZER;
43
44 int64_t GetRefreshTypesFlagOnlyEssentialData() {
45 // This is the only non-optional data in the Process as defined by the API in
46 // processes.idl.
47 return task_management::REFRESH_TYPE_NACL;
48 }
49
50 // This does not include memory. The memory refresh flag will only be added once
51 // a listener to OnUpdatedWithMemory event is added.
52 int64_t GetRefreshTypesFlagIncludeOptionalData() {
53 return GetRefreshTypesFlagOnlyEssentialData() |
54 task_management::REFRESH_TYPE_CPU |
55 task_management::REFRESH_TYPE_NETWORK_USAGE |
56 task_management::REFRESH_TYPE_SQLITE_MEMORY |
57 task_management::REFRESH_TYPE_V8_MEMORY |
58 task_management::REFRESH_TYPE_WEBCACHE_STATS;
59 }
58 60
59 scoped_ptr<api::processes::Cache> CreateCacheData( 61 scoped_ptr<api::processes::Cache> CreateCacheData(
60 const blink::WebCache::ResourceTypeStat& stat) { 62 const blink::WebCache::ResourceTypeStat& stat) {
61 scoped_ptr<api::processes::Cache> cache(new api::processes::Cache()); 63 scoped_ptr<api::processes::Cache> cache(new api::processes::Cache);
Devlin 2016/03/03 23:12:43 revert this change
afakhry 2016/03/08 01:37:29 Done.
62 cache->size = static_cast<double>(stat.size); 64 cache->size = static_cast<double>(stat.size);
63 cache->live_size = static_cast<double>(stat.liveSize); 65 cache->live_size = static_cast<double>(stat.liveSize);
64 return cache; 66 return cache;
65 } 67 }
66 68
67 api::processes::ProcessType GetProcessType(TaskManagerModel* model, 69 api::processes::ProcessType GetProcessType(
68 int index) { 70 task_management::Task::Type task_type) {
69 // Determine process type. 71 switch (task_type) {
70 task_manager::Resource::Type resource_type = model->GetResourceType(index); 72 case task_management::Task::BROWSER:
71 switch (resource_type) {
72 case task_manager::Resource::BROWSER:
73 return api::processes::PROCESS_TYPE_BROWSER; 73 return api::processes::PROCESS_TYPE_BROWSER;
74 74
75 case task_manager::Resource::RENDERER: 75 case task_management::Task::RENDERER:
76 return api::processes::PROCESS_TYPE_RENDERER; 76 return api::processes::PROCESS_TYPE_RENDERER;
77 77
78 case task_manager::Resource::EXTENSION: 78 case task_management::Task::EXTENSION:
79 case task_manager::Resource::GUEST: 79 case task_management::Task::GUEST:
80 return api::processes::PROCESS_TYPE_EXTENSION; 80 return api::processes::PROCESS_TYPE_EXTENSION;
81 81
82 case task_manager::Resource::NOTIFICATION: 82 case task_management::Task::PLUGIN:
83 return api::processes::PROCESS_TYPE_NOTIFICATION;
84
85 case task_manager::Resource::PLUGIN:
86 return api::processes::PROCESS_TYPE_PLUGIN; 83 return api::processes::PROCESS_TYPE_PLUGIN;
87 84
88 case task_manager::Resource::WORKER: 85 case task_management::Task::WORKER:
89 return api::processes::PROCESS_TYPE_WORKER; 86 return api::processes::PROCESS_TYPE_WORKER;
90 87
91 case task_manager::Resource::NACL: 88 case task_management::Task::NACL:
92 return api::processes::PROCESS_TYPE_NACL; 89 return api::processes::PROCESS_TYPE_NACL;
93 90
94 case task_manager::Resource::UTILITY: 91 case task_management::Task::UTILITY:
95 return api::processes::PROCESS_TYPE_UTILITY; 92 return api::processes::PROCESS_TYPE_UTILITY;
96 93
97 case task_manager::Resource::GPU: 94 case task_management::Task::GPU:
98 return api::processes::PROCESS_TYPE_GPU; 95 return api::processes::PROCESS_TYPE_GPU;
99 96
100 case task_manager::Resource::ZYGOTE: 97 case task_management::Task::UNKNOWN:
101 case task_manager::Resource::SANDBOX_HELPER: 98 case task_management::Task::ARC:
102 case task_manager::Resource::UNKNOWN: 99 case task_management::Task::SANDBOX_HELPER:
100 case task_management::Task::ZYGOTE:
103 return api::processes::PROCESS_TYPE_OTHER; 101 return api::processes::PROCESS_TYPE_OTHER;
104 } 102 }
105 103
106 NOTREACHED() << "Unknown resource type."; 104 NOTREACHED() << "Unknown task type.";
107 return api::processes::PROCESS_TYPE_NONE; 105 return api::processes::PROCESS_TYPE_NONE;
108 } 106 }
109 107
110 void FillTabsForProcess(int process_id, api::processes::Process* out_process) { 108 // Fills |out_process| with the data of the process in which the task with |id|
109 // is running. If |include_optional| is true, this function will fill the
110 // optional fields in |api::processes::Process| except for |private_memory|,
111 // which should be filled later if needed.
112 void FillProcessData(
113 task_management::TaskId id,
114 task_management::TaskManagerInterface* task_manager,
115 bool include_optional,
116 api::processes::Process* out_process) {
111 DCHECK(out_process); 117 DCHECK(out_process);
112 118
113 // The tabs list only makes sense for render processes, so if we don't find 119 out_process->id = task_manager->GetChildProcessUniqueId(id);
114 // one, just return the empty list. 120 out_process->os_process_id = task_manager->GetProcessId(id);
115 content::RenderProcessHost* rph = 121 out_process->type = GetProcessType(task_manager->GetType(id));
116 content::RenderProcessHost::FromID(process_id); 122 out_process->profile = base::UTF16ToUTF8(task_manager->GetProfileName(id));
117 if (!rph) 123 out_process->nacl_debug_port = task_manager->GetNaClDebugStubPort(id);
118 return; 124
119 125 // Collect the tab IDs of all the tasks sharing this renderer if any.
120 int tab_id = -1; 126 const task_management::TaskIdList tasks_on_process =
121 // We need to loop through all the RVHs to ensure we collect the set of all 127 task_manager->GetIdsOfTasksSharingSameProcess(id);
122 // tabs using this renderer process. 128 for (const auto& task_id : tasks_on_process) {
123 scoped_ptr<content::RenderWidgetHostIterator> widgets( 129 linked_ptr<api::processes::TaskInfo> task_info(
124 content::RenderWidgetHost::GetRenderWidgetHosts()); 130 new api::processes::TaskInfo);
Devlin 2016/03/03 23:12:43 nit: explicit ctor
afakhry 2016/03/08 01:37:29 Done.
125 while (content::RenderWidgetHost* widget = widgets->GetNextHost()) { 131 task_info->title = base::UTF16ToUTF8(task_manager->GetTitle(task_id));
126 if (widget->GetProcess()->GetID() != process_id) 132 const int tab_id = task_manager->GetTabId(task_id);
127 continue; 133 if (tab_id != -1)
128 134 task_info->tab_id.reset(new int(tab_id));
129 content::RenderViewHost* host = content::RenderViewHost::From(widget); 135
130 content::WebContents* contents = 136 out_process->tasks.push_back(task_info);
131 content::WebContents::FromRenderViewHost(host); 137 }
132 if (contents) {
133 tab_id = ExtensionTabUtil::GetTabId(contents);
134 if (tab_id != -1)
135 out_process->tabs.push_back(tab_id);
136 }
137 }
138 }
139
140 // This function fills |out_process| with the data of the process with
141 // |process_id|. For memory details, which are not added by this function,
142 // the callers need to use AddMemoryDetails.
143 void FillProcessData(int process_id,
144 TaskManagerModel* model,
145 int index,
146 bool include_optional,
147 api::processes::Process* out_process) {
148 DCHECK(out_process);
149
150 out_process->id = process_id;
151 out_process->os_process_id = model->GetProcessId(index);
152 out_process->type = GetProcessType(model, index);
153 out_process->title = base::UTF16ToUTF8(model->GetResourceTitle(index));
154 out_process->profile =
155 base::UTF16ToUTF8(model->GetResourceProfileName(index));
156 out_process->nacl_debug_port = model->GetNaClDebugStubPort(index);
157
158 FillTabsForProcess(process_id, out_process);
159 138
160 // If we don't need to include the optional properties, just return now. 139 // If we don't need to include the optional properties, just return now.
161 if (!include_optional) 140 if (!include_optional)
162 return; 141 return;
163 142
164 out_process->cpu.reset(new double(model->GetCPUUsage(index))); 143 out_process->cpu.reset(new double(task_manager->GetCpuUsage(id)));
165 144
166 size_t mem = 0; 145 out_process->network.reset(new double(static_cast<double>(
167 if (model->GetV8Memory(index, &mem)) { 146 task_manager->GetProcessTotalNetworkUsage(id))));
147
148 int64_t v8_allocated;
Devlin 2016/03/03 23:12:43 initialize these
afakhry 2016/03/08 01:37:29 Done.
149 int64_t v8_used;
150 if (task_manager->GetV8Memory(id, &v8_allocated, & v8_used)) {
Devlin 2016/03/03 23:12:43 nit: no space between & and v8_used (would git cl
afakhry 2016/03/08 01:37:29 Done. Yes it does catch it.
168 out_process->js_memory_allocated.reset(new double(static_cast<double>( 151 out_process->js_memory_allocated.reset(new double(static_cast<double>(
169 mem))); 152 v8_allocated)));
170 } 153 out_process->js_memory_used.reset(new double(static_cast<double>(v8_used)));
171 154 }
172 if (model->GetV8MemoryUsed(index, &mem)) 155
173 out_process->js_memory_used.reset(new double(static_cast<double>(mem))); 156 const int64_t sqlite_bytes = task_manager->GetSqliteMemoryUsed(id);
174 157 if (sqlite_bytes != -1) {
175 if (model->GetSqliteMemoryUsedBytes(index, &mem)) 158 out_process->sqlite_memory.reset(new double(static_cast<double>(
176 out_process->sqlite_memory.reset(new double(static_cast<double>(mem))); 159 sqlite_bytes)));
160 }
177 161
178 blink::WebCache::ResourceTypeStats cache_stats; 162 blink::WebCache::ResourceTypeStats cache_stats;
179 if (model->GetWebCoreCacheStats(index, &cache_stats)) { 163 if (task_manager->GetWebCacheStats(id, &cache_stats)) {
180 out_process->image_cache = CreateCacheData(cache_stats.images); 164 out_process->image_cache = CreateCacheData(cache_stats.images);
181 out_process->script_cache = CreateCacheData(cache_stats.scripts); 165 out_process->script_cache = CreateCacheData(cache_stats.scripts);
182 out_process->css_cache = CreateCacheData(cache_stats.cssStyleSheets); 166 out_process->css_cache = CreateCacheData(cache_stats.cssStyleSheets);
183 } 167 }
184 168 }
185 // Network is reported by the TaskManager per resource (tab), not per
186 // process, therefore we need to iterate through the group of resources
187 // and aggregate the data.
188 int64_t net = 0;
189 int length = model->GetGroupRangeForResource(index).second;
190 for (int i = 0; i < length; ++i)
191 net += model->GetNetworkUsage(index + i);
192 out_process->network.reset(new double(static_cast<double>(net)));
193 }
194
195 // Since memory details are expensive to gather, we don't do it by default.
196 // This function is a helper to add memory details data to an existing
197 // Process object |out_process|.
198 void AddMemoryDetails(TaskManagerModel* model,
199 int index,
200 api::processes::Process* out_process) {
201 DCHECK(out_process);
202
203 size_t mem;
204 int64_t pr_mem =
205 model->GetPrivateMemory(index, &mem) ? static_cast<int64_t>(mem) : -1;
206 out_process->private_memory.reset(new double(static_cast<double>(pr_mem)));
207 }
208
209 #endif // defined(ENABLE_TASK_MANAGER)
210 169
211 } // namespace 170 } // namespace
212 171
172 ////////////////////////////////////////////////////////////////////////////////
173 // ProcessesEventRouter:
174 ////////////////////////////////////////////////////////////////////////////////
175
213 ProcessesEventRouter::ProcessesEventRouter(content::BrowserContext* context) 176 ProcessesEventRouter::ProcessesEventRouter(content::BrowserContext* context)
214 : browser_context_(context), listeners_(0), task_manager_listening_(false) { 177 : task_management::TaskManagerObserver(
215 #if defined(ENABLE_TASK_MANAGER) 178 base::TimeDelta::FromSeconds(1),
Devlin 2016/03/03 23:12:43 If we don't have any listeners for OnUpdated[WithM
afakhry 2016/03/08 01:37:29 True. This doesn't add an observer to the task man
Devlin 2016/03/08 21:27:22 Right. The case I'm trying to defend against is t
Devlin 2016/03/09 15:16:12 Looks like you missed this one?
afakhry 2016/03/09 18:46:36 Yes, I did. Thanks for the reminder. All events on
216 model_ = TaskManager::GetInstance()->model(); 179 GetRefreshTypesFlagIncludeOptionalData()),
217 model_->AddObserver(this); 180 browser_context_(context),
218 181 listeners_(0) {
219 registrar_.Add(this, content::NOTIFICATION_RENDER_WIDGET_HOST_HANG,
220 content::NotificationService::AllSources());
221 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
222 content::NotificationService::AllSources());
223 #endif // defined(ENABLE_TASK_MANAGER)
224 } 182 }
225 183
226 ProcessesEventRouter::~ProcessesEventRouter() { 184 ProcessesEventRouter::~ProcessesEventRouter() {
227 #if defined(ENABLE_TASK_MANAGER) 185 if (observed_task_manager()) {
228 registrar_.Remove(this, content::NOTIFICATION_RENDER_WIDGET_HOST_HANG, 186 task_management::TaskManagerInterface::GetTaskManager()->RemoveObserver(
229 content::NotificationService::AllSources()); 187 this);
230 registrar_.Remove(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED, 188 }
231 content::NotificationService::AllSources());
232
233 if (task_manager_listening_)
234 model_->StopListening();
235
236 model_->RemoveObserver(this);
237 #endif // defined(ENABLE_TASK_MANAGER)
238 } 189 }
239 190
240 void ProcessesEventRouter::ListenerAdded() { 191 void ProcessesEventRouter::ListenerAdded() {
241 #if defined(ENABLE_TASK_MANAGER) 192 // Do we need to update memory usage?
242 // The task manager has its own ref count to balance other callers of 193 if (HasEventListeners(api::processes::OnUpdatedWithMemory::kEventName))
243 // StartUpdating/StopUpdating. 194 AddRefreshType(task_management::REFRESH_TYPE_MEMORY);
244 model_->StartUpdating(); 195
245 #endif // defined(ENABLE_TASK_MANAGER) 196 if (listeners_++ == 0) {
246 ++listeners_; 197 // The first listener to be added.
198 task_management::TaskManagerInterface::GetTaskManager()->AddObserver(this);
199 }
247 } 200 }
248 201
249 void ProcessesEventRouter::ListenerRemoved() { 202 void ProcessesEventRouter::ListenerRemoved() {
250 DCHECK_GT(listeners_, 0); 203 // No more listeners for memory usage?
251 --listeners_; 204 if (!HasEventListeners(api::processes::OnUpdatedWithMemory::kEventName))
252 #if defined(ENABLE_TASK_MANAGER) 205 RemoveRefreshType(task_management::REFRESH_TYPE_MEMORY);
253 // The task manager has its own ref count to balance other callers of 206
254 // StartUpdating/StopUpdating. 207 if (--listeners_ == 0) {
255 model_->StopUpdating(); 208 // Last listener to be removed.
256 #endif // defined(ENABLE_TASK_MANAGER) 209 task_management::TaskManagerInterface::GetTaskManager()->RemoveObserver(
257 } 210 this);
258 211 }
259 void ProcessesEventRouter::StartTaskManagerListening() { 212 }
260 #if defined(ENABLE_TASK_MANAGER) 213
261 if (!task_manager_listening_) { 214 void ProcessesEventRouter::OnTaskAdded(task_management::TaskId id) {
262 model_->StartListening();
263 task_manager_listening_ = true;
264 }
265 #endif // defined(ENABLE_TASK_MANAGER)
266 }
267
268 void ProcessesEventRouter::Observe(
269 int type,
270 const content::NotificationSource& source,
271 const content::NotificationDetails& details) {
272
273 switch (type) {
274 case content::NOTIFICATION_RENDER_WIDGET_HOST_HANG:
275 ProcessHangEvent(
276 content::Source<content::RenderWidgetHost>(source).ptr());
277 break;
278 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED:
279 ProcessClosedEvent(
280 content::Source<content::RenderProcessHost>(source).ptr(),
281 content::Details<content::RenderProcessHost::RendererClosedDetails>(
282 details).ptr());
283 break;
284 default:
285 NOTREACHED() << "Unexpected observe of type " << type;
286 }
287 return;
288 }
289
290 void ProcessesEventRouter::OnItemsAdded(int start, int length) {
291 #if defined(ENABLE_TASK_MANAGER)
292 DCHECK_EQ(length, 1);
293 if (!HasEventListeners(api::processes::OnCreated::kEventName)) 215 if (!HasEventListeners(api::processes::OnCreated::kEventName))
294 return; 216 return;
295 217
296 // If the item being added is not the first one in the group, find the base 218 // Is this the first task to be created on the process and hence its creation
297 // index and use it for retrieving the process data. 219 // corresponds to the creation of the process?
298 if (!model_->IsResourceFirstInGroup(start)) 220 if (observed_task_manager()->GetNumberOfTasksOnSameProcess(id) != 1)
299 start = model_->GetGroupIndexForResource(start); 221 return;
222
223 // Ignore tasks that don't have a valid child process host ID like ARC
224 // processes, as well as the browser process (onCreate() shouldn't report the
225 // creation of the browser process).
226 const int child_process_host_id =
227 observed_task_manager()->GetChildProcessUniqueId(id);
228 if (child_process_host_id == content::ChildProcessHost::kInvalidUniqueID ||
229 child_process_host_id == 0) {
230 return;
231 }
300 232
301 api::processes::Process process; 233 api::processes::Process process;
302 FillProcessData(model_->GetUniqueChildProcessId(start), model_, start, 234 FillProcessData(id, observed_task_manager(), false, &process);
303 false /* include_optional */, &process);
304 DispatchEvent(events::PROCESSES_ON_CREATED, 235 DispatchEvent(events::PROCESSES_ON_CREATED,
305 api::processes::OnCreated::kEventName, 236 api::processes::OnCreated::kEventName,
306 api::processes::OnCreated::Create(process)); 237 api::processes::OnCreated::Create(process));
307 #endif // defined(ENABLE_TASK_MANAGER) 238 }
308 } 239
309 240 void ProcessesEventRouter::OnTaskToBeRemoved(task_management::TaskId id) {
310 void ProcessesEventRouter::OnItemsChanged(int start, int length) { 241 if (!HasEventListeners(api::processes::OnExited::kEventName))
311 #if defined(ENABLE_TASK_MANAGER) 242 return;
312 // If we don't have any listeners, return immediately. 243
313 if (listeners_ == 0) 244 // Is this the last task to be removed from the process, and hence its removal
Devlin 2016/03/03 23:12:43 Common code between this and OnTaskAdded could be
afakhry 2016/03/08 01:37:29 Done.
314 return; 245 // corresponds to the termination of the process?
315 246 if (observed_task_manager()->GetNumberOfTasksOnSameProcess(id) != 1)
316 if (!model_) 247 return;
317 return; 248
318 249 // Ignore tasks that don't have a valid child process host ID like ARC
319 // We need to know which type of onUpdated events to fire and whether to 250 // processes, as well as the browser process (onExited() shouldn't report the
320 // collect memory or not. 251 // exit of the browser process).
321 bool updated = HasEventListeners(api::processes::OnUpdated::kEventName); 252 const int child_process_host_id =
322 bool updated_memory = 253 observed_task_manager()->GetChildProcessUniqueId(id);
254 if (child_process_host_id == content::ChildProcessHost::kInvalidUniqueID ||
255 child_process_host_id == 0) {
256 return;
257 }
258
259 int exit_code = 0;
260 base::TerminationStatus status = base::TERMINATION_STATUS_STILL_RUNNING;
261 observed_task_manager()->GetTerminationStatus(id, &status, &exit_code);
262
263 DispatchEvent(events::PROCESSES_ON_EXITED,
264 api::processes::OnExited::kEventName,
265 api::processes::OnExited::Create(child_process_host_id,
266 status,
267 exit_code));
268 }
269
270 void ProcessesEventRouter::OnTasksRefreshedWithBackgroundCalculations(
271 const task_management::TaskIdList& task_ids) {
272 const bool has_on_updated_listeners =
273 HasEventListeners(api::processes::OnUpdated::kEventName);
274 const bool has_on_updated_with_memory_listeners =
323 HasEventListeners(api::processes::OnUpdatedWithMemory::kEventName); 275 HasEventListeners(api::processes::OnUpdatedWithMemory::kEventName);
324 if (!updated && !updated_memory) 276
325 return; 277 if (!has_on_updated_listeners && !has_on_updated_with_memory_listeners)
326 278 return;
279
280 // Get the data of tasks sharing the same process only once.
281 std::set<base::ProcessId> seen_processes;
327 base::DictionaryValue processes_dictionary; 282 base::DictionaryValue processes_dictionary;
328 for (int i = start; i < start + length; ++i) { 283 for (const auto& task_id : task_ids) {
329 if (model_->IsResourceFirstInGroup(i)) { 284 // We are not interested in tasks, but rather the processes on which they
330 int id = model_->GetUniqueChildProcessId(i); 285 // run.
331 api::processes::Process process; 286 const base::ProcessId proc_id =
332 FillProcessData(id, model_, i, true /* include_optional */, &process); 287 observed_task_manager()->GetProcessId(task_id);
333 if (updated_memory) 288 if (seen_processes.count(proc_id))
334 AddMemoryDetails(model_, i, &process); 289 continue;
335 processes_dictionary.Set(base::IntToString(id), process.ToValue()); 290
291 const int child_process_host_id =
292 observed_task_manager()->GetChildProcessUniqueId(task_id);
293 // Ignore tasks that don't have a valid child process host ID like ARC
294 // processes. We report the browser process info here though.
295 if (child_process_host_id == content::ChildProcessHost::kInvalidUniqueID)
296 continue;
297
298 seen_processes.insert(proc_id);
299 api::processes::Process process;
300 FillProcessData(task_id, observed_task_manager(), true, &process);
Devlin 2016/03/03 23:12:43 doc anonymous bool
afakhry 2016/03/08 01:37:29 Done here and in all.
301
302 if (has_on_updated_with_memory_listeners) {
303 // Append the private memory usage to the process data.
304 const int64_t private_memory =
305 observed_task_manager()->GetPrivateMemoryUsage(task_id);
306 process.private_memory.reset(new double(static_cast<double>(
307 private_memory)));
336 } 308 }
337 } 309
338 310 // Store each process indexed by the string version of its ChildProcessHost
339 if (updated) { 311 // ID.
312 processes_dictionary.Set(base::IntToString(child_process_host_id),
313 process.ToValue());
314 }
315
316 // Done with data collection. Now dispatch the appropriate events according to
317 // the present listeners.
318 DCHECK(has_on_updated_listeners || has_on_updated_with_memory_listeners);
319 if (has_on_updated_listeners) {
340 api::processes::OnUpdated::Processes processes; 320 api::processes::OnUpdated::Processes processes;
341 processes.additional_properties.MergeDictionary(&processes_dictionary); 321 processes.additional_properties.MergeDictionary(&processes_dictionary);
342 // NOTE: If there are listeners to the updates with memory as well, 322 // NOTE: If there are listeners to the updates with memory as well,
343 // listeners to onUpdated (without memory) will also get the memory info 323 // listeners to onUpdated (without memory) will also get the memory info
344 // of processes as an added bonus. 324 // of processes as an added bonus.
345 DispatchEvent(events::PROCESSES_ON_UPDATED, 325 DispatchEvent(events::PROCESSES_ON_UPDATED,
346 api::processes::OnUpdated::kEventName, 326 api::processes::OnUpdated::kEventName,
347 api::processes::OnUpdated::Create(processes)); 327 api::processes::OnUpdated::Create(processes));
348 } 328 }
349 329
350 if (updated_memory) { 330 if (has_on_updated_with_memory_listeners) {
351 api::processes::OnUpdatedWithMemory::Processes processes; 331 api::processes::OnUpdatedWithMemory::Processes processes;
352 processes.additional_properties.MergeDictionary(&processes_dictionary); 332 processes.additional_properties.MergeDictionary(&processes_dictionary);
353 DispatchEvent(events::PROCESSES_ON_UPDATED_WITH_MEMORY, 333 DispatchEvent(events::PROCESSES_ON_UPDATED_WITH_MEMORY,
354 api::processes::OnUpdatedWithMemory::kEventName, 334 api::processes::OnUpdatedWithMemory::kEventName,
355 api::processes::OnUpdatedWithMemory::Create(processes));} 335 api::processes::OnUpdatedWithMemory::Create(processes));
356 #endif // defined(ENABLE_TASK_MANAGER) 336 }
357 } 337 }
358 338
359 void ProcessesEventRouter::OnItemsToBeRemoved(int start, int length) { 339 void ProcessesEventRouter::OnTaskUnresponsive(task_management::TaskId id) {
360 #if defined(ENABLE_TASK_MANAGER)
361 DCHECK_EQ(length, 1);
362
363 if (!HasEventListeners(api::processes::OnExited::kEventName))
364 return;
365
366 // Process exit for renderer processes has the data about exit code and
367 // termination status, therefore we will rely on notifications and not on
368 // the Task Manager data. We do use the rest of this method for non-renderer
369 // processes.
370 if (model_->GetResourceType(start) == task_manager::Resource::RENDERER)
371 return;
372
373 DispatchEvent(events::PROCESSES_ON_EXITED,
374 api::processes::OnExited::kEventName,
375 api::processes::OnExited::Create(
376 model_->GetUniqueChildProcessId(start),
377 0 /* exit_type */,
378 0 /* exit_code */));
379 #endif // defined(ENABLE_TASK_MANAGER)
380 }
381
382 void ProcessesEventRouter::ProcessHangEvent(content::RenderWidgetHost* widget) {
383 #if defined(ENABLE_TASK_MANAGER)
384 if (!HasEventListeners(api::processes::OnUnresponsive::kEventName)) 340 if (!HasEventListeners(api::processes::OnUnresponsive::kEventName))
385 return; 341 return;
386 342
387 int count = model_->ResourceCount(); 343 api::processes::Process process;
388 int id = widget->GetProcess()->GetID(); 344 FillProcessData(id, observed_task_manager(), false, &process);
389 345 DispatchEvent(events::PROCESSES_ON_UNRESPONSIVE,
390 for (int i = 0; i < count; ++i) { 346 api::processes::OnUnresponsive::kEventName,
391 if (model_->IsResourceFirstInGroup(i)) { 347 api::processes::OnUnresponsive::Create(process));
392 if (id == model_->GetUniqueChildProcessId(i)) {
393 api::processes::Process process;
394 FillProcessData(id, model_, i, false /* include_optional */, &process);
395 DispatchEvent(events::PROCESSES_ON_UNRESPONSIVE,
396 api::processes::OnUnresponsive::kEventName,
397 api::processes::OnUnresponsive::Create(process));
398 return;
399 }
400 }
401 }
402 #endif // defined(ENABLE_TASK_MANAGER)
403 }
404
405 void ProcessesEventRouter::ProcessClosedEvent(
406 content::RenderProcessHost* rph,
407 content::RenderProcessHost::RendererClosedDetails* details) {
408 #if defined(ENABLE_TASK_MANAGER)
409 if (!HasEventListeners(api::processes::OnExited::kEventName))
410 return;
411
412 DispatchEvent(events::PROCESSES_ON_EXITED,
413 api::processes::OnExited::kEventName,
414 api::processes::OnExited::Create(rph->GetID(),
415 details->status,
416 details->exit_code));
417 #endif // defined(ENABLE_TASK_MANAGER)
418 } 348 }
419 349
420 void ProcessesEventRouter::DispatchEvent( 350 void ProcessesEventRouter::DispatchEvent(
421 events::HistogramValue histogram_value, 351 events::HistogramValue histogram_value,
422 const std::string& event_name, 352 const std::string& event_name,
423 scoped_ptr<base::ListValue> event_args) { 353 scoped_ptr<base::ListValue> event_args) const {
424 EventRouter* event_router = EventRouter::Get(browser_context_); 354 EventRouter* event_router = EventRouter::Get(browser_context_);
425 if (event_router) { 355 if (event_router) {
426 scoped_ptr<Event> event( 356 scoped_ptr<Event> event(
427 new Event(histogram_value, event_name, std::move(event_args))); 357 new Event(histogram_value, event_name, std::move(event_args)));
428 event_router->BroadcastEvent(std::move(event)); 358 event_router->BroadcastEvent(std::move(event));
429 } 359 }
430 } 360 }
431 361
432 bool ProcessesEventRouter::HasEventListeners(const std::string& event_name) { 362 bool ProcessesEventRouter::HasEventListeners(
363 const std::string& event_name) const {
433 EventRouter* event_router = EventRouter::Get(browser_context_); 364 EventRouter* event_router = EventRouter::Get(browser_context_);
434 return event_router && event_router->HasEventListener(event_name); 365 return event_router && event_router->HasEventListener(event_name);
435 } 366 }
436 367
368 ////////////////////////////////////////////////////////////////////////////////
369 // ProcessesAPI:
370 ////////////////////////////////////////////////////////////////////////////////
371
437 ProcessesAPI::ProcessesAPI(content::BrowserContext* context) 372 ProcessesAPI::ProcessesAPI(content::BrowserContext* context)
438 : browser_context_(context) { 373 : browser_context_(context) {
439 EventRouter* event_router = EventRouter::Get(browser_context_); 374 EventRouter* event_router = EventRouter::Get(browser_context_);
440 // Monitor when the following events are being listened to in order to know 375 // Monitor when the following events are being listened to in order to know
441 // when to start the task manager. 376 // when to start the task manager.
442 event_router->RegisterObserver(this, api::processes::OnUpdated::kEventName); 377 event_router->RegisterObserver(this, api::processes::OnUpdated::kEventName);
443 event_router->RegisterObserver( 378 event_router->RegisterObserver(
444 this, api::processes::OnUpdatedWithMemory::kEventName); 379 this, api::processes::OnUpdatedWithMemory::kEventName);
445 event_router->RegisterObserver(this, api::processes::OnCreated::kEventName); 380 event_router->RegisterObserver(this, api::processes::OnCreated::kEventName);
446 event_router->RegisterObserver(this, 381 event_router->RegisterObserver(this,
447 api::processes::OnUnresponsive::kEventName); 382 api::processes::OnUnresponsive::kEventName);
448 event_router->RegisterObserver(this, api::processes::OnExited::kEventName); 383 event_router->RegisterObserver(this, api::processes::OnExited::kEventName);
449 } 384 }
450 385
451 ProcessesAPI::~ProcessesAPI() { 386 ProcessesAPI::~ProcessesAPI() {
387 // This object has already been unregistered as an observer in Shutdown().
452 } 388 }
453 389
454 void ProcessesAPI::Shutdown() {
455 EventRouter::Get(browser_context_)->UnregisterObserver(this);
456 }
457
458 static base::LazyInstance<BrowserContextKeyedAPIFactory<ProcessesAPI> >
459 g_factory = LAZY_INSTANCE_INITIALIZER;
460
461 // static 390 // static
462 BrowserContextKeyedAPIFactory<ProcessesAPI>* 391 BrowserContextKeyedAPIFactory<ProcessesAPI>*
463 ProcessesAPI::GetFactoryInstance() { 392 ProcessesAPI::GetFactoryInstance() {
464 return g_factory.Pointer(); 393 return g_processes_api_factory.Pointer();
465 } 394 }
466 395
467 // static 396 // static
468 ProcessesAPI* ProcessesAPI::Get(content::BrowserContext* context) { 397 ProcessesAPI* ProcessesAPI::Get(content::BrowserContext* context) {
469 return BrowserContextKeyedAPIFactory<ProcessesAPI>::Get(context); 398 return BrowserContextKeyedAPIFactory<ProcessesAPI>::Get(context);
470 } 399 }
471 400
401 void ProcessesAPI::Shutdown() {
402 EventRouter::Get(browser_context_)->UnregisterObserver(this);
403 }
404
405 void ProcessesAPI::OnListenerAdded(const EventListenerInfo& details) {
406 // The ProcessesEventRouter will observe the TaskManager as long as there are
407 // listeners for the processes.onUpdated/.onUpdatedWithMemory/.onCreated ...
408 // etc. events.
409 processes_event_router()->ListenerAdded();
410 }
411
412 void ProcessesAPI::OnListenerRemoved(const EventListenerInfo& details) {
413 // If a processes.onUpdated/.onUpdatedWithMemory/.onCreated ... etc. event
414 // listener is removed (or a process with one exits), then we let the
415 // extension API know that it has one fewer listener.
416 processes_event_router()->ListenerRemoved();
417 }
418
472 ProcessesEventRouter* ProcessesAPI::processes_event_router() { 419 ProcessesEventRouter* ProcessesAPI::processes_event_router() {
473 if (!processes_event_router_) 420 if (!processes_event_router_.get())
474 processes_event_router_.reset(new ProcessesEventRouter(browser_context_)); 421 processes_event_router_.reset(new ProcessesEventRouter(browser_context_));
475 return processes_event_router_.get(); 422 return processes_event_router_.get();
476 } 423 }
477 424
478 void ProcessesAPI::OnListenerAdded(const EventListenerInfo& details) {
479 // We lazily tell the TaskManager to start updating when listeners to the
480 // processes.onUpdated or processes.onUpdatedWithMemory events arrive.
481 processes_event_router()->ListenerAdded();
482 }
483
484 void ProcessesAPI::OnListenerRemoved(const EventListenerInfo& details) {
485 // If a processes.onUpdated or processes.onUpdatedWithMemory event listener
486 // is removed (or a process with one exits), then we let the extension API
487 // know that it has one fewer listener.
488 processes_event_router()->ListenerRemoved();
489 }
490
491 //////////////////////////////////////////////////////////////////////////////// 425 ////////////////////////////////////////////////////////////////////////////////
492 // ProcessesGetProcessIdForTabFunction: 426 // ProcessesGetProcessIdForTabFunction:
493 //////////////////////////////////////////////////////////////////////////////// 427 ////////////////////////////////////////////////////////////////////////////////
494 428
495 ProcessesGetProcessIdForTabFunction::ProcessesGetProcessIdForTabFunction()
496 : tab_id_(-1) {
497 }
498
499 ExtensionFunction::ResponseAction ProcessesGetProcessIdForTabFunction::Run() { 429 ExtensionFunction::ResponseAction ProcessesGetProcessIdForTabFunction::Run() {
500 #if defined(ENABLE_TASK_MANAGER) 430 // For this function, the task manager doesn't even need to be running.
501 scoped_ptr<api::processes::GetProcessIdForTab::Params> params( 431 scoped_ptr<api::processes::GetProcessIdForTab::Params> params(
502 api::processes::GetProcessIdForTab::Params::Create(*args_)); 432 api::processes::GetProcessIdForTab::Params::Create(*args_));
503 EXTENSION_FUNCTION_VALIDATE(params.get()); 433 EXTENSION_FUNCTION_VALIDATE(params.get());
504 tab_id_ = params->tab_id; 434
505 435 const int tab_id = params->tab_id;
506 if (tab_id_ < 0) { 436 content::WebContents* contents = nullptr;
507 return RespondNow(Error(errors::kInavlidArgument,
508 base::IntToString(tab_id_)));
509 }
510
511 // Add a reference, which is balanced in GetProcessIdForTab to keep the object
512 // around and allow for the callback to be invoked.
513 AddRef();
514
515 // If the task manager is already listening, just post a task to execute
516 // which will invoke the callback once we have returned from this function.
517 // Otherwise, wait for the notification that the task manager is done with
518 // the data gathering.
519 if (ProcessesAPI::Get(Profile::FromBrowserContext(browser_context()))
520 ->processes_event_router()
521 ->is_task_manager_listening()) {
522 base::ThreadTaskRunnerHandle::Get()->PostTask(
523 FROM_HERE,
524 base::Bind(&ProcessesGetProcessIdForTabFunction::GetProcessIdForTab,
525 this));
526 } else {
527 TaskManager::GetInstance()->model()->RegisterOnDataReadyCallback(
528 base::Bind(&ProcessesGetProcessIdForTabFunction::GetProcessIdForTab,
529 this));
530
531 ProcessesAPI::Get(Profile::FromBrowserContext(browser_context()))
532 ->processes_event_router()
533 ->StartTaskManagerListening();
534 }
535
536 return RespondLater();
537 #else
538 return RespondNow(Error(errors::kExtensionNotSupported));
539 #endif // defined(ENABLE_TASK_MANAGER)
540 }
541
542 void ProcessesGetProcessIdForTabFunction::GetProcessIdForTab() {
543 content::WebContents* contents = NULL;
544 int tab_index = -1; 437 int tab_index = -1;
545 if (!ExtensionTabUtil::GetTabById( 438 if (!ExtensionTabUtil::GetTabById(
546 tab_id_, 439 tab_id,
547 Profile::FromBrowserContext(browser_context()), 440 Profile::FromBrowserContext(browser_context()),
548 include_incognito(), 441 include_incognito(),
549 nullptr, 442 nullptr,
550 nullptr, 443 nullptr,
551 &contents, 444 &contents,
552 &tab_index)) { 445 &tab_index)) {
553 Respond(Error(tabs_constants::kTabNotFoundError, 446 return RespondNow(Error(tabs_constants::kTabNotFoundError,
554 base::IntToString(tab_id_))); 447 base::IntToString(tab_id)));
555 } else { 448 }
556 int process_id = contents->GetRenderProcessHost()->GetID(); 449
557 Respond(ArgumentList( 450 const int process_id = contents->GetRenderProcessHost()->GetID();
558 api::processes::GetProcessIdForTab::Results::Create(process_id))); 451 return RespondNow(ArgumentList(
559 } 452 api::processes::GetProcessIdForTab::Results::Create(process_id)));
560 453 }
561 // Balance the AddRef in the Run. 454
562 Release(); 455 ////////////////////////////////////////////////////////////////////////////////
563 } 456 // ProcessesTerminateFunction:
564 457 ////////////////////////////////////////////////////////////////////////////////
565 ////////////////////////////////////////////////////////////////////////////////
566 // ProcessesTerminateFunction
567 ////////////////////////////////////////////////////////////////////////////////
568
569 ProcessesTerminateFunction::ProcessesTerminateFunction() : process_id_(-1) {
570 }
571 458
572 ExtensionFunction::ResponseAction ProcessesTerminateFunction::Run() { 459 ExtensionFunction::ResponseAction ProcessesTerminateFunction::Run() {
573 #if defined(ENABLE_TASK_MANAGER) 460 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
461
462 // For this function, the task manager doesn't even need to be running.
574 scoped_ptr<api::processes::Terminate::Params> params( 463 scoped_ptr<api::processes::Terminate::Params> params(
575 api::processes::Terminate::Params::Create(*args_)); 464 api::processes::Terminate::Params::Create(*args_));
576 EXTENSION_FUNCTION_VALIDATE(params.get()); 465 EXTENSION_FUNCTION_VALIDATE(params.get());
577 process_id_ = params->process_id; 466
578 467 child_process_host_id_ = params->process_id;
579 // Add a reference, which is balanced in TerminateProcess to keep the object 468 if (child_process_host_id_ < 0) {
580 // around and allow for the callback to be invoked. 469 return RespondNow(Error(errors::kInvalidArgument,
581 AddRef(); 470 base::IntToString(child_process_host_id_)));
582 471 } else if (child_process_host_id_ == 0) {
583 // If the task manager is already listening, just post a task to execute 472 // Cannot kill the browser process.
584 // which will invoke the callback once we have returned from this function. 473 return RespondNow(Error(errors::kNotAllowedToTerminate,
585 // Otherwise, wait for the notification that the task manager is done with 474 base::IntToString(child_process_host_id_)));
586 // the data gathering. 475 }
587 if (ProcessesAPI::Get(Profile::FromBrowserContext(browser_context())) 476
588 ->processes_event_router() 477 content::BrowserThread::PostTaskAndReplyWithResult(
589 ->is_task_manager_listening()) { 478 content::BrowserThread::IO,
590 base::ThreadTaskRunnerHandle::Get()->PostTask( 479 FROM_HERE,
591 FROM_HERE, base::Bind(&ProcessesTerminateFunction::TerminateProcess, 480 base::Bind(&ProcessesTerminateFunction::GetProcessHandleIO,
592 this)); 481 this,
593 } else { 482 child_process_host_id_),
594 TaskManager::GetInstance()->model()->RegisterOnDataReadyCallback( 483 base::Bind(&ProcessesTerminateFunction::OnProcessHandleUI, this));
595 base::Bind(&ProcessesTerminateFunction::TerminateProcess, this)); 484
596 485 // Promise to respond later.
597 ProcessesAPI::Get(Profile::FromBrowserContext(browser_context()))
598 ->processes_event_router()
599 ->StartTaskManagerListening();
600 }
601
602 return RespondLater(); 486 return RespondLater();
603 #else 487 }
604 return RespondNow(Error(errors::kExtensionNotSupported)); 488
605 #endif // defined(ENABLE_TASK_MANAGER) 489 base::ProcessHandle ProcessesTerminateFunction::GetProcessHandleIO(
606 } 490 int child_process_host_id) const {
607 491 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
608 void ProcessesTerminateFunction::TerminateProcess() { 492
609 #if defined(ENABLE_TASK_MANAGER) 493 auto* host = content::BrowserChildProcessHost::FromID(child_process_host_id);
610 TaskManagerModel* model = TaskManager::GetInstance()->model(); 494 if (host)
611 495 return host->GetData().handle;
612 bool found = false; 496
613 for (int i = 0, count = model->ResourceCount(); i < count; ++i) { 497 return base::kNullProcessHandle;
614 if (model->IsResourceFirstInGroup(i) && 498 }
615 process_id_ == model->GetUniqueChildProcessId(i)) { 499
616 base::ProcessHandle process_handle = model->GetProcess(i); 500 void ProcessesTerminateFunction::OnProcessHandleUI(base::ProcessHandle handle) {
Devlin 2016/03/03 23:12:43 I don't know much about base::ProcessHandles and B
afakhry 2016/03/08 01:37:29 I'm not sure, but the task manager is already usin
617 if (process_handle == base::GetCurrentProcessHandle()) { 501 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
618 // Cannot kill the browser process. 502
619 // TODO(kalman): Are there other sensitive processes? 503 if (handle == base::kNullProcessHandle) {
620 Respond(Error(errors::kNotAllowedToTerminate, 504 // If we didn't get anything from BrowserChildProcessHost, then it could be
621 base::IntToString(process_id_))); 505 // a renderer.
622 } else { 506 auto* render_process_host =
623 base::Process process = 507 content::RenderProcessHost::FromID(child_process_host_id_);
624 base::Process::DeprecatedGetProcessFromHandle(process_handle); 508 if (render_process_host)
Devlin 2016/03/03 23:12:43 Would it be cheaper to try this before we do the t
afakhry 2016/03/08 01:37:29 Great idea! Done.
625 bool did_terminate = 509 handle = render_process_host->GetHandle();
626 process.Terminate(content::RESULT_CODE_KILLED, true); 510 }
627 if (did_terminate) 511
628 UMA_HISTOGRAM_COUNTS("ChildProcess.KilledByExtensionAPI", 1); 512 if (handle == base::kNullProcessHandle) {
629 513 Respond(Error(errors::kProcessNotFound,
630 Respond(ArgumentList( 514 base::IntToString(child_process_host_id_)));
631 api::processes::Terminate::Results::Create(did_terminate))); 515 return;
632 } 516 }
633 found = true; 517
634 break; 518 if (handle == base::GetCurrentProcessHandle()) {
635 } 519 // Cannot kill the browser process.
636 } 520 Respond(Error(errors::kNotAllowedToTerminate,
637 521 base::IntToString(child_process_host_id_)));
638 if (!found) 522 return;
639 Respond(Error(errors::kProcessNotFound, base::IntToString(process_id_))); 523 }
640 524
641 // Balance the AddRef in the Run. 525 base::Process process = base::Process::Open(base::GetProcId(handle));
642 Release(); 526 const bool did_terminate =
643 #endif // defined(ENABLE_TASK_MANAGER) 527 process.Terminate(content::RESULT_CODE_KILLED, true);
644 } 528 if (did_terminate)
645 529 UMA_HISTOGRAM_COUNTS("ChildProcess.KilledByExtensionAPI", 1);
646 //////////////////////////////////////////////////////////////////////////////// 530
647 // ProcessesGetProcessInfoFunction 531 Respond(ArgumentList(
532 api::processes::Terminate::Results::Create(did_terminate)));
533 }
534
535 ////////////////////////////////////////////////////////////////////////////////
536 // ProcessesGetProcessInfoFunction:
648 //////////////////////////////////////////////////////////////////////////////// 537 ////////////////////////////////////////////////////////////////////////////////
649 538
650 ProcessesGetProcessInfoFunction::ProcessesGetProcessInfoFunction() 539 ProcessesGetProcessInfoFunction::ProcessesGetProcessInfoFunction()
651 #if defined(ENABLE_TASK_MANAGER) 540 : task_management::TaskManagerObserver(
652 : memory_(false) 541 base::TimeDelta::FromSeconds(1),
653 #endif 542 GetRefreshTypesFlagOnlyEssentialData()) {
654 {
655 } 543 }
656 544
657 ExtensionFunction::ResponseAction ProcessesGetProcessInfoFunction::Run() { 545 ExtensionFunction::ResponseAction ProcessesGetProcessInfoFunction::Run() {
658 #if defined(ENABLE_TASK_MANAGER)
659 scoped_ptr<api::processes::GetProcessInfo::Params> params( 546 scoped_ptr<api::processes::GetProcessInfo::Params> params(
660 api::processes::GetProcessInfo::Params::Create(*args_)); 547 api::processes::GetProcessInfo::Params::Create(*args_));
661 EXTENSION_FUNCTION_VALIDATE(params.get()); 548 EXTENSION_FUNCTION_VALIDATE(params.get());
662 if (params->process_ids.as_integer) 549 if (params->process_ids.as_integer)
663 process_ids_.push_back(*params->process_ids.as_integer); 550 process_host_ids_.push_back(*params->process_ids.as_integer);
664 else 551 else
665 process_ids_.swap(*params->process_ids.as_integers); 552 process_host_ids_.swap(*params->process_ids.as_integers);
666 553
667 memory_ = params->include_memory; 554 include_memory_ = params->include_memory;
668 555 if (include_memory_)
669 // Add a reference, which is balanced in GatherProcessInfo to keep the object 556 AddRefreshType(task_management::REFRESH_TYPE_MEMORY);
670 // around and allow for the callback to be invoked. 557
558 // Keep this object alive until the first of either OnTasksRefreshed() or
559 // OnTasksRefreshedWithBackgroundCalculations() is received depending on
560 // |include_memory_|.
671 AddRef(); 561 AddRef();
672 562
673 // If the task manager is already listening, just post a task to execute 563 // The task manager needs to be enabled for this function.
674 // which will invoke the callback once we have returned from this function. 564 // Start observing the task manager and wait for the next refresh event.
675 // Otherwise, wait for the notification that the task manager is done with 565 task_management::TaskManagerInterface::GetTaskManager()->AddObserver(this);
676 // the data gathering.
677 if (ProcessesAPI::Get(Profile::FromBrowserContext(browser_context()))
678 ->processes_event_router()
679 ->is_task_manager_listening()) {
680 base::ThreadTaskRunnerHandle::Get()->PostTask(
681 FROM_HERE,
682 base::Bind(&ProcessesGetProcessInfoFunction::GatherProcessInfo, this));
683 } else {
684 TaskManager::GetInstance()->model()->RegisterOnDataReadyCallback(
685 base::Bind(&ProcessesGetProcessInfoFunction::GatherProcessInfo, this));
686
687 ProcessesAPI::Get(Profile::FromBrowserContext(browser_context()))
688 ->processes_event_router()
689 ->StartTaskManagerListening();
690 }
691 566
692 return RespondLater(); 567 return RespondLater();
693 #else 568 }
694 return RespondNow(Error(errors::kExtensionNotSupported)); 569
695 #endif // defined(ENABLE_TASK_MANAGER) 570 void ProcessesGetProcessInfoFunction::OnTasksRefreshed(
696 } 571 const task_management::TaskIdList& task_ids) {
697 572 // Memory is background calculated and will be ready when
698 ProcessesGetProcessInfoFunction::~ProcessesGetProcessInfoFunction() { 573 // OnTasksRefreshedWithBackgroundCalculations() is invoked.
699 } 574 if (include_memory_)
700 575 return;
701 void ProcessesGetProcessInfoFunction::GatherProcessInfo() { 576
702 #if defined(ENABLE_TASK_MANAGER) 577 GatherDataAndRespond(task_ids);
703 TaskManagerModel* model = TaskManager::GetInstance()->model(); 578 }
704 api::processes::GetProcessInfo::Results::Processes processes; 579
705 580 void
581 ProcessesGetProcessInfoFunction::OnTasksRefreshedWithBackgroundCalculations(
582 const task_management::TaskIdList& task_ids) {
583 if (!include_memory_)
584 return;
585
586 GatherDataAndRespond(task_ids);
587 }
588
589 ProcessesGetProcessInfoFunction::~ProcessesGetProcessInfoFunction() {}
590
591 void ProcessesGetProcessInfoFunction::GatherDataAndRespond(
592 const task_management::TaskIdList& task_ids) {
706 // If there are no process IDs specified, it means we need to return all of 593 // If there are no process IDs specified, it means we need to return all of
707 // the ones we know of. 594 // the ones we know of.
708 if (process_ids_.size() == 0) { 595 const bool specific_processes_requested = !process_host_ids_.empty();
709 int resources = model->ResourceCount(); 596 std::set<base::ProcessId> seen_processes;
710 for (int i = 0; i < resources; ++i) { 597 // Create the results object as defined in the generated API from process.idl
711 if (model->IsResourceFirstInGroup(i)) { 598 // and fill it with the processes info.
712 int id = model->GetUniqueChildProcessId(i); 599 api::processes::GetProcessInfo::Results::Processes processes;
713 api::processes::Process process; 600 for (const auto& task_id : task_ids) {
714 FillProcessData(id, model, i, false, &process); 601 const base::ProcessId proc_id =
715 if (memory_) 602 observed_task_manager()->GetProcessId(task_id);
716 AddMemoryDetails(model, i, &process); 603 if (seen_processes.count(proc_id))
717 processes.additional_properties.Set(base::IntToString(id), 604 continue;
718 process.ToValue()); 605
719 } 606 const int child_process_host_id =
607 observed_task_manager()->GetChildProcessUniqueId(task_id);
608 // Ignore tasks that don't have a valid child process host ID like ARC
609 // processes. We report the browser process info here though.
610 if (child_process_host_id == content::ChildProcessHost::kInvalidUniqueID)
611 continue;
612
613 if (specific_processes_requested) {
614 // Note: we can't use |!process_host_ids_.empty()| directly in the above
615 // condition as we will erase from |process_host_ids_| below.
616 auto itr = std::find(process_host_ids_.begin(),
617 process_host_ids_.end(),
618 child_process_host_id);
619 if (itr == process_host_ids_.end())
620 continue;
621
622 // If found, we remove it from |process_host_ids|, so that at the end if
623 // anything remains in |process_host_ids|, those were invalid arguments
624 // that will be reported on the console.
625 process_host_ids_.erase(itr);
720 } 626 }
721 } else { 627
722 int resources = model->ResourceCount(); 628 seen_processes.insert(proc_id);
723 for (int i = 0; i < resources; ++i) { 629
724 if (model->IsResourceFirstInGroup(i)) { 630 // We do not include the optional data in this function results.
725 int id = model->GetUniqueChildProcessId(i); 631 api::processes::Process process;
726 std::vector<int>::iterator proc_id = std::find(process_ids_.begin(), 632 FillProcessData(task_id, observed_task_manager(), false, &process);
727 process_ids_.end(), id); 633
728 if (proc_id != process_ids_.end()) { 634 if (include_memory_) {
729 api::processes::Process process; 635 // Append the private memory usage to the process data.
730 FillProcessData(id, model, i, false, &process); 636 const int64_t private_memory =
731 if (memory_) 637 observed_task_manager()->GetPrivateMemoryUsage(task_id);
732 AddMemoryDetails(model, i, &process); 638 process.private_memory.reset(new double(static_cast<double>(
733 processes.additional_properties.Set(base::IntToString(id), 639 private_memory)));
734 process.ToValue());
735
736 process_ids_.erase(proc_id);
737 if (process_ids_.size() == 0)
738 break;
739 }
740 }
741 } 640 }
742 // If not all processes were found, log them to the extension's console to 641
743 // help the developer, but don't fail the API call. 642 // Store each process indexed by the string version of its
744 for (int pid : process_ids_) { 643 // ChildProcessHost ID.
745 WriteToConsole(content::CONSOLE_MESSAGE_LEVEL_ERROR, 644 processes.additional_properties.Set(
746 ErrorUtils::FormatErrorMessage(errors::kProcessNotFound, 645 base::IntToString(child_process_host_id),
747 base::IntToString(pid))); 646 process.ToValue());
748 } 647 }
648
649 // Report the invalid host ids sent in the arguments.
650 for (const auto& host_id : process_host_ids_) {
651 WriteToConsole(content::CONSOLE_MESSAGE_LEVEL_ERROR,
652 ErrorUtils::FormatErrorMessage(errors::kProcessNotFound,
653 base::IntToString(host_id)));
749 } 654 }
750 655
751 // Send the response. 656 // Send the response.
752 Respond(ArgumentList( 657 Respond(ArgumentList(
753 api::processes::GetProcessInfo::Results::Create(processes))); 658 api::processes::GetProcessInfo::Results::Create(processes)));
754 659
755 // Balance the AddRef in the Run. 660 // Stop observing the task manager, and balance the AddRef() in Run().
661 task_management::TaskManagerInterface::GetTaskManager()->RemoveObserver(this);
756 Release(); 662 Release();
757 #endif // defined(ENABLE_TASK_MANAGER)
758 } 663 }
759 664
760 } // namespace extensions 665 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698