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

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

Powered by Google App Engine
This is Rietveld 408576698