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

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: Devlin's comments 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>
12 10
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> >
Devlin 2016/03/08 21:27:22 nit: s/> >/>>
afakhry 2016/03/09 02:10:13 Done.
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());
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());
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 = 0;
149 int64_t v8_used = 0;
150 if (task_manager->GetV8Memory(id, &v8_allocated, &v8_used)) {
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),
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(
Devlin 2016/03/08 21:27:22 This looks like something that should happen in ~T
afakhry 2016/03/09 02:10:13 I'm not sure why I haven't thought of this before.
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 int child_process_host_id = 0;
297 // index and use it for retrieving the process data. 219 if (!ShouldReportOnCreatedOrOnExited(id, &child_process_host_id))
298 if (!model_->IsResourceFirstInGroup(start)) 220 return;
299 start = model_->GetGroupIndexForResource(start);
300 221
301 api::processes::Process process; 222 api::processes::Process process;
302 FillProcessData(model_->GetUniqueChildProcessId(start), model_, start, 223 FillProcessData(id,
303 false /* include_optional */, &process); 224 observed_task_manager(),
225 false, // include_optional
226 &process);
304 DispatchEvent(events::PROCESSES_ON_CREATED, 227 DispatchEvent(events::PROCESSES_ON_CREATED,
305 api::processes::OnCreated::kEventName, 228 api::processes::OnCreated::kEventName,
306 api::processes::OnCreated::Create(process)); 229 api::processes::OnCreated::Create(process));
307 #endif // defined(ENABLE_TASK_MANAGER) 230 }
308 } 231
309 232 void ProcessesEventRouter::OnTaskToBeRemoved(task_management::TaskId id) {
310 void ProcessesEventRouter::OnItemsChanged(int start, int length) { 233 if (!HasEventListeners(api::processes::OnExited::kEventName))
311 #if defined(ENABLE_TASK_MANAGER) 234 return;
312 // If we don't have any listeners, return immediately. 235
313 if (listeners_ == 0) 236 int child_process_host_id = 0;
314 return; 237 if (!ShouldReportOnCreatedOrOnExited(id, &child_process_host_id))
315 238 return;
316 if (!model_) 239
317 return; 240 int exit_code = 0;
318 241 base::TerminationStatus status = base::TERMINATION_STATUS_STILL_RUNNING;
319 // We need to know which type of onUpdated events to fire and whether to 242 observed_task_manager()->GetTerminationStatus(id, &status, &exit_code);
320 // collect memory or not. 243
321 bool updated = HasEventListeners(api::processes::OnUpdated::kEventName); 244 DispatchEvent(events::PROCESSES_ON_EXITED,
322 bool updated_memory = 245 api::processes::OnExited::kEventName,
246 api::processes::OnExited::Create(child_process_host_id,
247 status,
248 exit_code));
249 }
250
251 void ProcessesEventRouter::OnTasksRefreshedWithBackgroundCalculations(
252 const task_management::TaskIdList& task_ids) {
253 const bool has_on_updated_listeners =
254 HasEventListeners(api::processes::OnUpdated::kEventName);
255 const bool has_on_updated_with_memory_listeners =
323 HasEventListeners(api::processes::OnUpdatedWithMemory::kEventName); 256 HasEventListeners(api::processes::OnUpdatedWithMemory::kEventName);
324 if (!updated && !updated_memory) 257
325 return; 258 if (!has_on_updated_listeners && !has_on_updated_with_memory_listeners)
326 259 return;
260
261 // Get the data of tasks sharing the same process only once.
262 std::set<base::ProcessId> seen_processes;
327 base::DictionaryValue processes_dictionary; 263 base::DictionaryValue processes_dictionary;
328 for (int i = start; i < start + length; ++i) { 264 for (const auto& task_id : task_ids) {
329 if (model_->IsResourceFirstInGroup(i)) { 265 // We are not interested in tasks, but rather the processes on which they
330 int id = model_->GetUniqueChildProcessId(i); 266 // run.
331 api::processes::Process process; 267 const base::ProcessId proc_id =
332 FillProcessData(id, model_, i, true /* include_optional */, &process); 268 observed_task_manager()->GetProcessId(task_id);
333 if (updated_memory) 269 if (seen_processes.count(proc_id))
334 AddMemoryDetails(model_, i, &process); 270 continue;
335 processes_dictionary.Set(base::IntToString(id), process.ToValue()); 271
272 const int child_process_host_id =
273 observed_task_manager()->GetChildProcessUniqueId(task_id);
274 // Ignore tasks that don't have a valid child process host ID like ARC
275 // processes. We report the browser process info here though.
276 if (child_process_host_id == content::ChildProcessHost::kInvalidUniqueID)
277 continue;
278
279 seen_processes.insert(proc_id);
280 api::processes::Process process;
281 FillProcessData(task_id,
282 observed_task_manager(),
283 true, // include_optional
284 &process);
285
286 if (has_on_updated_with_memory_listeners) {
287 // Append the private memory usage to the process data.
288 const int64_t private_memory =
289 observed_task_manager()->GetPrivateMemoryUsage(task_id);
290 process.private_memory.reset(new double(static_cast<double>(
291 private_memory)));
336 } 292 }
337 } 293
338 294 // Store each process indexed by the string version of its ChildProcessHost
339 if (updated) { 295 // ID.
296 processes_dictionary.Set(base::IntToString(child_process_host_id),
297 process.ToValue());
298 }
299
300 // Done with data collection. Now dispatch the appropriate events according to
301 // the present listeners.
302 DCHECK(has_on_updated_listeners || has_on_updated_with_memory_listeners);
303 if (has_on_updated_listeners) {
340 api::processes::OnUpdated::Processes processes; 304 api::processes::OnUpdated::Processes processes;
341 processes.additional_properties.MergeDictionary(&processes_dictionary); 305 processes.additional_properties.MergeDictionary(&processes_dictionary);
342 // NOTE: If there are listeners to the updates with memory as well, 306 // NOTE: If there are listeners to the updates with memory as well,
343 // listeners to onUpdated (without memory) will also get the memory info 307 // listeners to onUpdated (without memory) will also get the memory info
344 // of processes as an added bonus. 308 // of processes as an added bonus.
345 DispatchEvent(events::PROCESSES_ON_UPDATED, 309 DispatchEvent(events::PROCESSES_ON_UPDATED,
346 api::processes::OnUpdated::kEventName, 310 api::processes::OnUpdated::kEventName,
347 api::processes::OnUpdated::Create(processes)); 311 api::processes::OnUpdated::Create(processes));
348 } 312 }
349 313
350 if (updated_memory) { 314 if (has_on_updated_with_memory_listeners) {
351 api::processes::OnUpdatedWithMemory::Processes processes; 315 api::processes::OnUpdatedWithMemory::Processes processes;
352 processes.additional_properties.MergeDictionary(&processes_dictionary); 316 processes.additional_properties.MergeDictionary(&processes_dictionary);
353 DispatchEvent(events::PROCESSES_ON_UPDATED_WITH_MEMORY, 317 DispatchEvent(events::PROCESSES_ON_UPDATED_WITH_MEMORY,
354 api::processes::OnUpdatedWithMemory::kEventName, 318 api::processes::OnUpdatedWithMemory::kEventName,
355 api::processes::OnUpdatedWithMemory::Create(processes));} 319 api::processes::OnUpdatedWithMemory::Create(processes));
356 #endif // defined(ENABLE_TASK_MANAGER) 320 }
357 } 321 }
358 322
359 void ProcessesEventRouter::OnItemsToBeRemoved(int start, int length) { 323 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)) 324 if (!HasEventListeners(api::processes::OnUnresponsive::kEventName))
385 return; 325 return;
386 326
387 int count = model_->ResourceCount(); 327 api::processes::Process process;
388 int id = widget->GetProcess()->GetID(); 328 FillProcessData(id,
389 329 observed_task_manager(),
390 for (int i = 0; i < count; ++i) { 330 false, // include_optional
391 if (model_->IsResourceFirstInGroup(i)) { 331 &process);
392 if (id == model_->GetUniqueChildProcessId(i)) { 332 DispatchEvent(events::PROCESSES_ON_UNRESPONSIVE,
393 api::processes::Process process; 333 api::processes::OnUnresponsive::kEventName,
394 FillProcessData(id, model_, i, false /* include_optional */, &process); 334 api::processes::OnUnresponsive::Create(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 } 335 }
419 336
420 void ProcessesEventRouter::DispatchEvent( 337 void ProcessesEventRouter::DispatchEvent(
421 events::HistogramValue histogram_value, 338 events::HistogramValue histogram_value,
422 const std::string& event_name, 339 const std::string& event_name,
423 scoped_ptr<base::ListValue> event_args) { 340 scoped_ptr<base::ListValue> event_args) const {
424 EventRouter* event_router = EventRouter::Get(browser_context_); 341 EventRouter* event_router = EventRouter::Get(browser_context_);
425 if (event_router) { 342 if (event_router) {
426 scoped_ptr<Event> event( 343 scoped_ptr<Event> event(
427 new Event(histogram_value, event_name, std::move(event_args))); 344 new Event(histogram_value, event_name, std::move(event_args)));
428 event_router->BroadcastEvent(std::move(event)); 345 event_router->BroadcastEvent(std::move(event));
429 } 346 }
430 } 347 }
431 348
432 bool ProcessesEventRouter::HasEventListeners(const std::string& event_name) { 349 bool ProcessesEventRouter::HasEventListeners(
350 const std::string& event_name) const {
433 EventRouter* event_router = EventRouter::Get(browser_context_); 351 EventRouter* event_router = EventRouter::Get(browser_context_);
434 return event_router && event_router->HasEventListener(event_name); 352 return event_router && event_router->HasEventListener(event_name);
435 } 353 }
436 354
355 bool ProcessesEventRouter::ShouldReportOnCreatedOrOnExited(
356 task_management::TaskId id,
357 int* out_child_process_host_id) const {
358 if (observed_task_manager()->GetNumberOfTasksOnSameProcess(id) != 1)
359 return false;
360
361 // Ignore tasks that don't have a valid child process host ID like ARC
362 // processes, as well as the browser process (onExited() shouldn't report the
363 // exit of the browser process).
364 *out_child_process_host_id =
365 observed_task_manager()->GetChildProcessUniqueId(id);
366 if (*out_child_process_host_id ==
367 content::ChildProcessHost::kInvalidUniqueID ||
368 *out_child_process_host_id == 0) {
369 return false;
370 }
371
372 return true;
373 }
374
375 ////////////////////////////////////////////////////////////////////////////////
376 // ProcessesAPI:
377 ////////////////////////////////////////////////////////////////////////////////
378
437 ProcessesAPI::ProcessesAPI(content::BrowserContext* context) 379 ProcessesAPI::ProcessesAPI(content::BrowserContext* context)
438 : browser_context_(context) { 380 : browser_context_(context) {
439 EventRouter* event_router = EventRouter::Get(browser_context_); 381 EventRouter* event_router = EventRouter::Get(browser_context_);
440 // Monitor when the following events are being listened to in order to know 382 // Monitor when the following events are being listened to in order to know
441 // when to start the task manager. 383 // when to start the task manager.
442 event_router->RegisterObserver(this, api::processes::OnUpdated::kEventName); 384 event_router->RegisterObserver(this, api::processes::OnUpdated::kEventName);
443 event_router->RegisterObserver( 385 event_router->RegisterObserver(
444 this, api::processes::OnUpdatedWithMemory::kEventName); 386 this, api::processes::OnUpdatedWithMemory::kEventName);
445 event_router->RegisterObserver(this, api::processes::OnCreated::kEventName); 387 event_router->RegisterObserver(this, api::processes::OnCreated::kEventName);
446 event_router->RegisterObserver(this, 388 event_router->RegisterObserver(this,
447 api::processes::OnUnresponsive::kEventName); 389 api::processes::OnUnresponsive::kEventName);
448 event_router->RegisterObserver(this, api::processes::OnExited::kEventName); 390 event_router->RegisterObserver(this, api::processes::OnExited::kEventName);
449 } 391 }
450 392
451 ProcessesAPI::~ProcessesAPI() { 393 ProcessesAPI::~ProcessesAPI() {
394 // This object has already been unregistered as an observer in Shutdown().
452 } 395 }
453 396
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 397 // static
462 BrowserContextKeyedAPIFactory<ProcessesAPI>* 398 BrowserContextKeyedAPIFactory<ProcessesAPI>*
463 ProcessesAPI::GetFactoryInstance() { 399 ProcessesAPI::GetFactoryInstance() {
464 return g_factory.Pointer(); 400 return g_processes_api_factory.Pointer();
465 } 401 }
466 402
467 // static 403 // static
468 ProcessesAPI* ProcessesAPI::Get(content::BrowserContext* context) { 404 ProcessesAPI* ProcessesAPI::Get(content::BrowserContext* context) {
469 return BrowserContextKeyedAPIFactory<ProcessesAPI>::Get(context); 405 return BrowserContextKeyedAPIFactory<ProcessesAPI>::Get(context);
470 } 406 }
471 407
408 void ProcessesAPI::Shutdown() {
409 EventRouter::Get(browser_context_)->UnregisterObserver(this);
410 }
411
412 void ProcessesAPI::OnListenerAdded(const EventListenerInfo& details) {
413 // The ProcessesEventRouter will observe the TaskManager as long as there are
414 // listeners for the processes.onUpdated/.onUpdatedWithMemory/.onCreated ...
415 // etc. events.
416 processes_event_router()->ListenerAdded();
417 }
418
419 void ProcessesAPI::OnListenerRemoved(const EventListenerInfo& details) {
420 // If a processes.onUpdated/.onUpdatedWithMemory/.onCreated ... etc. event
421 // listener is removed (or a process with one exits), then we let the
422 // extension API know that it has one fewer listener.
423 processes_event_router()->ListenerRemoved();
424 }
425
472 ProcessesEventRouter* ProcessesAPI::processes_event_router() { 426 ProcessesEventRouter* ProcessesAPI::processes_event_router() {
473 if (!processes_event_router_) 427 if (!processes_event_router_.get())
474 processes_event_router_.reset(new ProcessesEventRouter(browser_context_)); 428 processes_event_router_.reset(new ProcessesEventRouter(browser_context_));
475 return processes_event_router_.get(); 429 return processes_event_router_.get();
476 } 430 }
477 431
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 //////////////////////////////////////////////////////////////////////////////// 432 ////////////////////////////////////////////////////////////////////////////////
492 // ProcessesGetProcessIdForTabFunction: 433 // ProcessesGetProcessIdForTabFunction:
493 //////////////////////////////////////////////////////////////////////////////// 434 ////////////////////////////////////////////////////////////////////////////////
494 435
495 ProcessesGetProcessIdForTabFunction::ProcessesGetProcessIdForTabFunction()
496 : tab_id_(-1) {
497 }
498
499 ExtensionFunction::ResponseAction ProcessesGetProcessIdForTabFunction::Run() { 436 ExtensionFunction::ResponseAction ProcessesGetProcessIdForTabFunction::Run() {
500 #if defined(ENABLE_TASK_MANAGER) 437 // For this function, the task manager doesn't even need to be running.
501 scoped_ptr<api::processes::GetProcessIdForTab::Params> params( 438 scoped_ptr<api::processes::GetProcessIdForTab::Params> params(
502 api::processes::GetProcessIdForTab::Params::Create(*args_)); 439 api::processes::GetProcessIdForTab::Params::Create(*args_));
503 EXTENSION_FUNCTION_VALIDATE(params.get()); 440 EXTENSION_FUNCTION_VALIDATE(params.get());
504 tab_id_ = params->tab_id; 441
505 442 const int tab_id = params->tab_id;
506 if (tab_id_ < 0) { 443 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; 444 int tab_index = -1;
545 if (!ExtensionTabUtil::GetTabById( 445 if (!ExtensionTabUtil::GetTabById(
546 tab_id_, 446 tab_id,
547 Profile::FromBrowserContext(browser_context()), 447 Profile::FromBrowserContext(browser_context()),
548 include_incognito(), 448 include_incognito(),
549 nullptr, 449 nullptr,
550 nullptr, 450 nullptr,
551 &contents, 451 &contents,
552 &tab_index)) { 452 &tab_index)) {
553 Respond(Error(tabs_constants::kTabNotFoundError, 453 return RespondNow(Error(tabs_constants::kTabNotFoundError,
554 base::IntToString(tab_id_))); 454 base::IntToString(tab_id)));
555 } else { 455 }
556 int process_id = contents->GetRenderProcessHost()->GetID(); 456
557 Respond(ArgumentList( 457 const int process_id = contents->GetRenderProcessHost()->GetID();
558 api::processes::GetProcessIdForTab::Results::Create(process_id))); 458 return RespondNow(ArgumentList(
559 } 459 api::processes::GetProcessIdForTab::Results::Create(process_id)));
560 460 }
561 // Balance the AddRef in the Run. 461
562 Release(); 462 ////////////////////////////////////////////////////////////////////////////////
563 } 463 // ProcessesTerminateFunction:
564 464 ////////////////////////////////////////////////////////////////////////////////
565 ////////////////////////////////////////////////////////////////////////////////
566 // ProcessesTerminateFunction
567 ////////////////////////////////////////////////////////////////////////////////
568
569 ProcessesTerminateFunction::ProcessesTerminateFunction() : process_id_(-1) {
570 }
571 465
572 ExtensionFunction::ResponseAction ProcessesTerminateFunction::Run() { 466 ExtensionFunction::ResponseAction ProcessesTerminateFunction::Run() {
573 #if defined(ENABLE_TASK_MANAGER) 467 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
468
469 // For this function, the task manager doesn't even need to be running.
574 scoped_ptr<api::processes::Terminate::Params> params( 470 scoped_ptr<api::processes::Terminate::Params> params(
575 api::processes::Terminate::Params::Create(*args_)); 471 api::processes::Terminate::Params::Create(*args_));
576 EXTENSION_FUNCTION_VALIDATE(params.get()); 472 EXTENSION_FUNCTION_VALIDATE(params.get());
577 process_id_ = params->process_id; 473
578 474 child_process_host_id_ = params->process_id;
579 // Add a reference, which is balanced in TerminateProcess to keep the object 475 if (child_process_host_id_ < 0) {
580 // around and allow for the callback to be invoked. 476 return RespondNow(Error(errors::kInvalidArgument,
581 AddRef(); 477 base::IntToString(child_process_host_id_)));
582 478 } else if (child_process_host_id_ == 0) {
583 // If the task manager is already listening, just post a task to execute 479 // Cannot kill the browser process.
584 // which will invoke the callback once we have returned from this function. 480 return RespondNow(Error(errors::kNotAllowedToTerminate,
585 // Otherwise, wait for the notification that the task manager is done with 481 base::IntToString(child_process_host_id_)));
586 // the data gathering. 482 }
587 if (ProcessesAPI::Get(Profile::FromBrowserContext(browser_context())) 483
588 ->processes_event_router() 484 // Check if it's a renderer.
589 ->is_task_manager_listening()) { 485 base::ProcessHandle handle = base::kNullProcessHandle;
590 base::ThreadTaskRunnerHandle::Get()->PostTask( 486 auto* render_process_host =
591 FROM_HERE, base::Bind(&ProcessesTerminateFunction::TerminateProcess, 487 content::RenderProcessHost::FromID(child_process_host_id_);
592 this)); 488 if (render_process_host)
593 } else { 489 handle = render_process_host->GetHandle();
594 TaskManager::GetInstance()->model()->RegisterOnDataReadyCallback( 490
595 base::Bind(&ProcessesTerminateFunction::TerminateProcess, this)); 491 if (handle == base::kNullProcessHandle) {
Devlin 2016/03/08 21:27:22 Should this be an else to match the if on 488? Is
afakhry 2016/03/09 02:10:13 Yes if the renderer is still starting, but you are
596 492 // This could be a non-renderer child process like a plugin or a nacl
597 ProcessesAPI::Get(Profile::FromBrowserContext(browser_context())) 493 // process. Try to get its handle from the BrowserChildProcessHost on the
598 ->processes_event_router() 494 // IO thread.
599 ->StartTaskManagerListening(); 495 content::BrowserThread::PostTaskAndReplyWithResult(
600 } 496 content::BrowserThread::IO,
601 497 FROM_HERE,
602 return RespondLater(); 498 base::Bind(&ProcessesTerminateFunction::GetProcessHandleOnIO,
603 #else 499 this,
604 return RespondNow(Error(errors::kExtensionNotSupported)); 500 child_process_host_id_),
605 #endif // defined(ENABLE_TASK_MANAGER) 501 base::Bind(&ProcessesTerminateFunction::OnProcessHandleOnUI, this));
606 } 502
607 503 // Promise to respond later.
608 void ProcessesTerminateFunction::TerminateProcess() { 504 return RespondLater();
609 #if defined(ENABLE_TASK_MANAGER) 505 }
610 TaskManagerModel* model = TaskManager::GetInstance()->model(); 506
611 507 const char* error_message = nullptr;
Devlin 2016/03/08 21:27:22 These ten-ish lines can be shared between here and
afakhry 2016/03/09 02:10:13 Great suggestion. Thanks. Done.
612 bool found = false; 508 if (!CanTerminate(handle, &error_message)) {
613 for (int i = 0, count = model->ResourceCount(); i < count; ++i) { 509 return RespondNow(Error(error_message,
614 if (model->IsResourceFirstInGroup(i) && 510 base::IntToString(child_process_host_id_)));
615 process_id_ == model->GetUniqueChildProcessId(i)) { 511 }
616 base::ProcessHandle process_handle = model->GetProcess(i); 512
617 if (process_handle == base::GetCurrentProcessHandle()) { 513 // Terminate and respond now.
618 // Cannot kill the browser process. 514 const bool did_terminate = Terminate(handle);
619 // TODO(kalman): Are there other sensitive processes? 515 return RespondNow(ArgumentList(
620 Respond(Error(errors::kNotAllowedToTerminate, 516 api::processes::Terminate::Results::Create(did_terminate)));
621 base::IntToString(process_id_))); 517 }
622 } else { 518
623 base::Process process = 519 base::ProcessHandle ProcessesTerminateFunction::GetProcessHandleOnIO(
624 base::Process::DeprecatedGetProcessFromHandle(process_handle); 520 int child_process_host_id) const {
625 bool did_terminate = 521 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
626 process.Terminate(content::RESULT_CODE_KILLED, true); 522
627 if (did_terminate) 523 auto* host = content::BrowserChildProcessHost::FromID(child_process_host_id);
628 UMA_HISTOGRAM_COUNTS("ChildProcess.KilledByExtensionAPI", 1); 524 if (host)
629 525 return host->GetData().handle;
630 Respond(ArgumentList( 526
631 api::processes::Terminate::Results::Create(did_terminate))); 527 return base::kNullProcessHandle;
632 } 528 }
633 found = true; 529
634 break; 530 void ProcessesTerminateFunction::OnProcessHandleOnUI(
635 } 531 base::ProcessHandle handle) {
636 } 532 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
637 533
638 if (!found) 534 const char* error_message = nullptr;
639 Respond(Error(errors::kProcessNotFound, base::IntToString(process_id_))); 535 if (!CanTerminate(handle, &error_message)) {
640 536 Respond(Error(error_message, base::IntToString(child_process_host_id_)));
641 // Balance the AddRef in the Run. 537 return;
642 Release(); 538 }
643 #endif // defined(ENABLE_TASK_MANAGER) 539
644 } 540 // Terminate and respond.
645 541 const bool did_terminate = Terminate(handle);
646 //////////////////////////////////////////////////////////////////////////////// 542 Respond(ArgumentList(
647 // ProcessesGetProcessInfoFunction 543 api::processes::Terminate::Results::Create(did_terminate)));
544 }
545
546 bool ProcessesTerminateFunction::CanTerminate(
547 base::ProcessHandle handle,
548 const char** out_error_message) const {
549 if (handle == base::kNullProcessHandle) {
550 *out_error_message = errors::kProcessNotFound;
551 return false;
552 }
553
554 if (handle == base::GetCurrentProcessHandle()) {
555 // Cannot kill the browser process.
556 *out_error_message = errors::kNotAllowedToTerminate;
557 return false;
558 }
559
560 return true;
561 }
562
563 bool ProcessesTerminateFunction::Terminate(base::ProcessHandle handle) const {
564 base::Process process = base::Process::Open(base::GetProcId(handle));
565 if (!process.IsValid())
566 return false;
567
568 const bool did_terminate =
569 process.Terminate(content::RESULT_CODE_KILLED, true /* wait */);
570 if (did_terminate)
571 UMA_HISTOGRAM_COUNTS("ChildProcess.KilledByExtensionAPI", 1);
572
573 return did_terminate;
574 }
575
576 ////////////////////////////////////////////////////////////////////////////////
577 // ProcessesGetProcessInfoFunction:
648 //////////////////////////////////////////////////////////////////////////////// 578 ////////////////////////////////////////////////////////////////////////////////
649 579
650 ProcessesGetProcessInfoFunction::ProcessesGetProcessInfoFunction() 580 ProcessesGetProcessInfoFunction::ProcessesGetProcessInfoFunction()
651 #if defined(ENABLE_TASK_MANAGER) 581 : task_management::TaskManagerObserver(
652 : memory_(false) 582 base::TimeDelta::FromSeconds(1),
653 #endif 583 GetRefreshTypesFlagOnlyEssentialData()) {
654 {
655 } 584 }
656 585
657 ExtensionFunction::ResponseAction ProcessesGetProcessInfoFunction::Run() { 586 ExtensionFunction::ResponseAction ProcessesGetProcessInfoFunction::Run() {
658 #if defined(ENABLE_TASK_MANAGER)
659 scoped_ptr<api::processes::GetProcessInfo::Params> params( 587 scoped_ptr<api::processes::GetProcessInfo::Params> params(
660 api::processes::GetProcessInfo::Params::Create(*args_)); 588 api::processes::GetProcessInfo::Params::Create(*args_));
661 EXTENSION_FUNCTION_VALIDATE(params.get()); 589 EXTENSION_FUNCTION_VALIDATE(params.get());
662 if (params->process_ids.as_integer) 590 if (params->process_ids.as_integer)
663 process_ids_.push_back(*params->process_ids.as_integer); 591 process_host_ids_.push_back(*params->process_ids.as_integer);
664 else 592 else
665 process_ids_.swap(*params->process_ids.as_integers); 593 process_host_ids_.swap(*params->process_ids.as_integers);
666 594
667 memory_ = params->include_memory; 595 include_memory_ = params->include_memory;
668 596 if (include_memory_)
669 // Add a reference, which is balanced in GatherProcessInfo to keep the object 597 AddRefreshType(task_management::REFRESH_TYPE_MEMORY);
670 // around and allow for the callback to be invoked. 598
599 // Keep this object alive until the first of either OnTasksRefreshed() or
600 // OnTasksRefreshedWithBackgroundCalculations() is received depending on
601 // |include_memory_|.
671 AddRef(); 602 AddRef();
672 603
673 // If the task manager is already listening, just post a task to execute 604 // The task manager needs to be enabled for this function.
674 // which will invoke the callback once we have returned from this function. 605 // 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 606 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 607
692 return RespondLater(); 608 return RespondLater();
693 #else 609 }
694 return RespondNow(Error(errors::kExtensionNotSupported)); 610
695 #endif // defined(ENABLE_TASK_MANAGER) 611 void ProcessesGetProcessInfoFunction::OnTasksRefreshed(
696 } 612 const task_management::TaskIdList& task_ids) {
697 613 // Memory is background calculated and will be ready when
698 ProcessesGetProcessInfoFunction::~ProcessesGetProcessInfoFunction() { 614 // OnTasksRefreshedWithBackgroundCalculations() is invoked.
699 } 615 if (include_memory_)
700 616 return;
701 void ProcessesGetProcessInfoFunction::GatherProcessInfo() { 617
702 #if defined(ENABLE_TASK_MANAGER) 618 GatherDataAndRespond(task_ids);
703 TaskManagerModel* model = TaskManager::GetInstance()->model(); 619 }
704 api::processes::GetProcessInfo::Results::Processes processes; 620
705 621 void
622 ProcessesGetProcessInfoFunction::OnTasksRefreshedWithBackgroundCalculations(
623 const task_management::TaskIdList& task_ids) {
624 if (!include_memory_)
625 return;
626
627 GatherDataAndRespond(task_ids);
628 }
629
630 ProcessesGetProcessInfoFunction::~ProcessesGetProcessInfoFunction() {}
631
632 void ProcessesGetProcessInfoFunction::GatherDataAndRespond(
633 const task_management::TaskIdList& task_ids) {
706 // If there are no process IDs specified, it means we need to return all of 634 // If there are no process IDs specified, it means we need to return all of
707 // the ones we know of. 635 // the ones we know of.
708 if (process_ids_.size() == 0) { 636 const bool specific_processes_requested = !process_host_ids_.empty();
709 int resources = model->ResourceCount(); 637 std::set<base::ProcessId> seen_processes;
710 for (int i = 0; i < resources; ++i) { 638 // Create the results object as defined in the generated API from process.idl
711 if (model->IsResourceFirstInGroup(i)) { 639 // and fill it with the processes info.
712 int id = model->GetUniqueChildProcessId(i); 640 api::processes::GetProcessInfo::Results::Processes processes;
713 api::processes::Process process; 641 for (const auto& task_id : task_ids) {
714 FillProcessData(id, model, i, false, &process); 642 const base::ProcessId proc_id =
715 if (memory_) 643 observed_task_manager()->GetProcessId(task_id);
716 AddMemoryDetails(model, i, &process); 644 if (seen_processes.count(proc_id))
717 processes.additional_properties.Set(base::IntToString(id), 645 continue;
718 process.ToValue()); 646
719 } 647 const int child_process_host_id =
648 observed_task_manager()->GetChildProcessUniqueId(task_id);
649 // Ignore tasks that don't have a valid child process host ID like ARC
650 // processes. We report the browser process info here though.
651 if (child_process_host_id == content::ChildProcessHost::kInvalidUniqueID)
652 continue;
653
654 if (specific_processes_requested) {
655 // Note: we can't use |!process_host_ids_.empty()| directly in the above
656 // condition as we will erase from |process_host_ids_| below.
657 auto itr = std::find(process_host_ids_.begin(),
658 process_host_ids_.end(),
659 child_process_host_id);
660 if (itr == process_host_ids_.end())
661 continue;
662
663 // If found, we remove it from |process_host_ids|, so that at the end if
664 // anything remains in |process_host_ids|, those were invalid arguments
665 // that will be reported on the console.
666 process_host_ids_.erase(itr);
720 } 667 }
721 } else { 668
722 int resources = model->ResourceCount(); 669 seen_processes.insert(proc_id);
723 for (int i = 0; i < resources; ++i) { 670
724 if (model->IsResourceFirstInGroup(i)) { 671 // We do not include the optional data in this function results.
725 int id = model->GetUniqueChildProcessId(i); 672 api::processes::Process process;
726 std::vector<int>::iterator proc_id = std::find(process_ids_.begin(), 673 FillProcessData(task_id,
727 process_ids_.end(), id); 674 observed_task_manager(),
728 if (proc_id != process_ids_.end()) { 675 false, // include_optional
729 api::processes::Process process; 676 &process);
730 FillProcessData(id, model, i, false, &process); 677
731 if (memory_) 678 if (include_memory_) {
732 AddMemoryDetails(model, i, &process); 679 // Append the private memory usage to the process data.
733 processes.additional_properties.Set(base::IntToString(id), 680 const int64_t private_memory =
734 process.ToValue()); 681 observed_task_manager()->GetPrivateMemoryUsage(task_id);
735 682 process.private_memory.reset(new double(static_cast<double>(
736 process_ids_.erase(proc_id); 683 private_memory)));
737 if (process_ids_.size() == 0)
738 break;
739 }
740 }
741 } 684 }
742 // If not all processes were found, log them to the extension's console to 685
743 // help the developer, but don't fail the API call. 686 // Store each process indexed by the string version of its
744 for (int pid : process_ids_) { 687 // ChildProcessHost ID.
745 WriteToConsole(content::CONSOLE_MESSAGE_LEVEL_ERROR, 688 processes.additional_properties.Set(
746 ErrorUtils::FormatErrorMessage(errors::kProcessNotFound, 689 base::IntToString(child_process_host_id),
747 base::IntToString(pid))); 690 process.ToValue());
748 } 691 }
692
693 // Report the invalid host ids sent in the arguments.
694 for (const auto& host_id : process_host_ids_) {
695 WriteToConsole(content::CONSOLE_MESSAGE_LEVEL_ERROR,
696 ErrorUtils::FormatErrorMessage(errors::kProcessNotFound,
697 base::IntToString(host_id)));
749 } 698 }
750 699
751 // Send the response. 700 // Send the response.
752 Respond(ArgumentList( 701 Respond(ArgumentList(
753 api::processes::GetProcessInfo::Results::Create(processes))); 702 api::processes::GetProcessInfo::Results::Create(processes)));
754 703
755 // Balance the AddRef in the Run. 704 // Stop observing the task manager, and balance the AddRef() in Run().
705 task_management::TaskManagerInterface::GetTaskManager()->RemoveObserver(this);
756 Release(); 706 Release();
757 #endif // defined(ENABLE_TASK_MANAGER)
758 } 707 }
759 708
760 } // namespace extensions 709 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698