blob: 47907540040cbd37a018dfe232c9d1b42546e98b [file] [log] [blame]
Ronghua Wu231c3d12015-03-11 15:10:32 -07001/*
2**
3** Copyright 2015, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9** http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18//#define LOG_NDEBUG 0
19#define LOG_TAG "ResourceManagerService"
20#include <utils/Log.h>
21
22#include <binder/IServiceManager.h>
23#include <dirent.h>
24#include <media/stagefright/ProcessInfo.h>
25#include <string.h>
26#include <sys/types.h>
27#include <sys/stat.h>
28#include <sys/time.h>
29#include <unistd.h>
30
31#include "ResourceManagerService.h"
Ronghua Wua8ec8fc2015-05-07 13:58:22 -070032#include "ServiceLog.h"
Ronghua Wu231c3d12015-03-11 15:10:32 -070033
34namespace android {
35
36template <typename T>
37static String8 getString(const Vector<T> &items) {
38 String8 itemsStr;
39 for (size_t i = 0; i < items.size(); ++i) {
40 itemsStr.appendFormat("%s ", items[i].toString().string());
41 }
42 return itemsStr;
43}
44
45static bool hasResourceType(String8 type, Vector<MediaResource> resources) {
46 for (size_t i = 0; i < resources.size(); ++i) {
47 if (resources[i].mType == type) {
48 return true;
49 }
50 }
51 return false;
52}
53
54static bool hasResourceType(String8 type, ResourceInfos infos) {
55 for (size_t i = 0; i < infos.size(); ++i) {
56 if (hasResourceType(type, infos[i].resources)) {
57 return true;
58 }
59 }
60 return false;
61}
62
63static ResourceInfos& getResourceInfosForEdit(
64 int pid,
65 PidResourceInfosMap& map) {
66 ssize_t index = map.indexOfKey(pid);
67 if (index < 0) {
68 // new pid
69 ResourceInfos infosForPid;
70 map.add(pid, infosForPid);
71 }
72
73 return map.editValueFor(pid);
74}
75
76static ResourceInfo& getResourceInfoForEdit(
77 int64_t clientId,
78 const sp<IResourceManagerClient> client,
79 ResourceInfos& infos) {
80 for (size_t i = 0; i < infos.size(); ++i) {
81 if (infos[i].clientId == clientId) {
82 return infos.editItemAt(i);
83 }
84 }
85 ResourceInfo info;
86 info.clientId = clientId;
87 info.client = client;
88 infos.push_back(info);
89 return infos.editItemAt(infos.size() - 1);
90}
91
Ronghua Wua8ec8fc2015-05-07 13:58:22 -070092status_t ResourceManagerService::dump(int fd, const Vector<String16>& /* args */) {
Ronghua Wu8f9dd872015-04-23 15:24:25 -070093 Mutex::Autolock lock(mLock);
94
95 String8 result;
96 const size_t SIZE = 256;
97 char buffer[SIZE];
98
dcashmanf86a4412015-09-11 09:33:01 -070099 if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
100 result.format("Permission Denial: "
101 "can't dump ResourceManagerService from pid=%d, uid=%d\n",
102 IPCThreadState::self()->getCallingPid(),
103 IPCThreadState::self()->getCallingUid());
104 write(fd, result.string(), result.size());
105 return PERMISSION_DENIED;
106 }
107
Ronghua Wu8f9dd872015-04-23 15:24:25 -0700108 snprintf(buffer, SIZE, "ResourceManagerService: %p\n", this);
109 result.append(buffer);
110 result.append(" Policies:\n");
111 snprintf(buffer, SIZE, " SupportsMultipleSecureCodecs: %d\n", mSupportsMultipleSecureCodecs);
112 result.append(buffer);
113 snprintf(buffer, SIZE, " SupportsSecureWithNonSecureCodec: %d\n", mSupportsSecureWithNonSecureCodec);
114 result.append(buffer);
115
Ronghua Wua8ec8fc2015-05-07 13:58:22 -0700116 result.append(" Processes:\n");
Ronghua Wu8f9dd872015-04-23 15:24:25 -0700117 for (size_t i = 0; i < mMap.size(); ++i) {
118 snprintf(buffer, SIZE, " Pid: %d\n", mMap.keyAt(i));
119 result.append(buffer);
120
121 const ResourceInfos &infos = mMap.valueAt(i);
122 for (size_t j = 0; j < infos.size(); ++j) {
Ronghua Wua8ec8fc2015-05-07 13:58:22 -0700123 result.append(" Client:\n");
Ronghua Wu8f9dd872015-04-23 15:24:25 -0700124 snprintf(buffer, SIZE, " Id: %lld\n", (long long)infos[j].clientId);
125 result.append(buffer);
126
127 snprintf(buffer, SIZE, " Name: %s\n", infos[j].client->getName().string());
128 result.append(buffer);
129
130 Vector<MediaResource> resources = infos[j].resources;
Ronghua Wua8ec8fc2015-05-07 13:58:22 -0700131 result.append(" Resources:\n");
Ronghua Wu8f9dd872015-04-23 15:24:25 -0700132 for (size_t k = 0; k < resources.size(); ++k) {
133 snprintf(buffer, SIZE, " %s\n", resources[k].toString().string());
134 result.append(buffer);
135 }
136 }
137 }
Ronghua Wu022ed722015-05-11 15:15:09 -0700138 result.append(" Events logs (most recent at top):\n");
139 result.append(mServiceLog->toString(" " /* linePrefix */));
Ronghua Wu8f9dd872015-04-23 15:24:25 -0700140
141 write(fd, result.string(), result.size());
142 return OK;
143}
144
Ronghua Wu231c3d12015-03-11 15:10:32 -0700145ResourceManagerService::ResourceManagerService()
146 : mProcessInfo(new ProcessInfo()),
Ronghua Wua8ec8fc2015-05-07 13:58:22 -0700147 mServiceLog(new ServiceLog()),
Ronghua Wu231c3d12015-03-11 15:10:32 -0700148 mSupportsMultipleSecureCodecs(true),
149 mSupportsSecureWithNonSecureCodec(true) {}
150
151ResourceManagerService::ResourceManagerService(sp<ProcessInfoInterface> processInfo)
152 : mProcessInfo(processInfo),
Ronghua Wua8ec8fc2015-05-07 13:58:22 -0700153 mServiceLog(new ServiceLog()),
Ronghua Wu231c3d12015-03-11 15:10:32 -0700154 mSupportsMultipleSecureCodecs(true),
155 mSupportsSecureWithNonSecureCodec(true) {}
156
157ResourceManagerService::~ResourceManagerService() {}
158
159void ResourceManagerService::config(const Vector<MediaResourcePolicy> &policies) {
Ronghua Wua8ec8fc2015-05-07 13:58:22 -0700160 String8 log = String8::format("config(%s)", getString(policies).string());
161 mServiceLog->add(log);
Ronghua Wu231c3d12015-03-11 15:10:32 -0700162
163 Mutex::Autolock lock(mLock);
164 for (size_t i = 0; i < policies.size(); ++i) {
165 String8 type = policies[i].mType;
Ronghua Wu9ba21b92015-04-21 14:23:06 -0700166 String8 value = policies[i].mValue;
Ronghua Wu231c3d12015-03-11 15:10:32 -0700167 if (type == kPolicySupportsMultipleSecureCodecs) {
Ronghua Wu9ba21b92015-04-21 14:23:06 -0700168 mSupportsMultipleSecureCodecs = (value == "true");
Ronghua Wu231c3d12015-03-11 15:10:32 -0700169 } else if (type == kPolicySupportsSecureWithNonSecureCodec) {
Ronghua Wu9ba21b92015-04-21 14:23:06 -0700170 mSupportsSecureWithNonSecureCodec = (value == "true");
Ronghua Wu231c3d12015-03-11 15:10:32 -0700171 }
172 }
173}
174
175void ResourceManagerService::addResource(
176 int pid,
177 int64_t clientId,
178 const sp<IResourceManagerClient> client,
179 const Vector<MediaResource> &resources) {
Ronghua Wua8ec8fc2015-05-07 13:58:22 -0700180 String8 log = String8::format("addResource(pid %d, clientId %lld, resources %s)",
Ronghua Wu231c3d12015-03-11 15:10:32 -0700181 pid, (long long) clientId, getString(resources).string());
Ronghua Wua8ec8fc2015-05-07 13:58:22 -0700182 mServiceLog->add(log);
Ronghua Wu231c3d12015-03-11 15:10:32 -0700183
184 Mutex::Autolock lock(mLock);
185 ResourceInfos& infos = getResourceInfosForEdit(pid, mMap);
186 ResourceInfo& info = getResourceInfoForEdit(clientId, client, infos);
Ronghua Wu67e7f542015-03-13 10:47:08 -0700187 // TODO: do the merge instead of append.
Ronghua Wu231c3d12015-03-11 15:10:32 -0700188 info.resources.appendVector(resources);
189}
190
Ronghua Wu37c89242015-07-15 12:23:48 -0700191void ResourceManagerService::removeResource(int pid, int64_t clientId) {
192 String8 log = String8::format(
193 "removeResource(pid %d, clientId %lld)",
194 pid, (long long) clientId);
Ronghua Wua8ec8fc2015-05-07 13:58:22 -0700195 mServiceLog->add(log);
Ronghua Wu231c3d12015-03-11 15:10:32 -0700196
197 Mutex::Autolock lock(mLock);
Ronghua Wu37c89242015-07-15 12:23:48 -0700198 ssize_t index = mMap.indexOfKey(pid);
199 if (index < 0) {
200 ALOGV("removeResource: didn't find pid %d for clientId %lld", pid, (long long) clientId);
201 return;
202 }
Ronghua Wu231c3d12015-03-11 15:10:32 -0700203 bool found = false;
Ronghua Wu37c89242015-07-15 12:23:48 -0700204 ResourceInfos &infos = mMap.editValueAt(index);
205 for (size_t j = 0; j < infos.size(); ++j) {
206 if (infos[j].clientId == clientId) {
207 j = infos.removeAt(j);
208 found = true;
Ronghua Wu231c3d12015-03-11 15:10:32 -0700209 break;
210 }
211 }
212 if (!found) {
213 ALOGV("didn't find client");
214 }
215}
216
Ronghua Wu05d89f12015-07-07 16:47:42 -0700217void ResourceManagerService::getClientForResource_l(
218 int callingPid, const MediaResource *res, Vector<sp<IResourceManagerClient>> *clients) {
219 if (res == NULL) {
220 return;
221 }
222 sp<IResourceManagerClient> client;
223 if (getLowestPriorityBiggestClient_l(callingPid, res->mType, &client)) {
224 clients->push_back(client);
225 }
226}
227
Ronghua Wu231c3d12015-03-11 15:10:32 -0700228bool ResourceManagerService::reclaimResource(
229 int callingPid, const Vector<MediaResource> &resources) {
Ronghua Wua8ec8fc2015-05-07 13:58:22 -0700230 String8 log = String8::format("reclaimResource(callingPid %d, resources %s)",
Ronghua Wu231c3d12015-03-11 15:10:32 -0700231 callingPid, getString(resources).string());
Ronghua Wua8ec8fc2015-05-07 13:58:22 -0700232 mServiceLog->add(log);
Ronghua Wu231c3d12015-03-11 15:10:32 -0700233
234 Vector<sp<IResourceManagerClient>> clients;
235 {
236 Mutex::Autolock lock(mLock);
Ronghua Wu05d89f12015-07-07 16:47:42 -0700237 const MediaResource *secureCodec = NULL;
238 const MediaResource *nonSecureCodec = NULL;
239 const MediaResource *graphicMemory = NULL;
Ronghua Wu231c3d12015-03-11 15:10:32 -0700240 for (size_t i = 0; i < resources.size(); ++i) {
241 String8 type = resources[i].mType;
Ronghua Wu05d89f12015-07-07 16:47:42 -0700242 if (resources[i].mType == kResourceSecureCodec) {
243 secureCodec = &resources[i];
Ronghua Wu231c3d12015-03-11 15:10:32 -0700244 } else if (type == kResourceNonSecureCodec) {
Ronghua Wu05d89f12015-07-07 16:47:42 -0700245 nonSecureCodec = &resources[i];
246 } else if (type == kResourceGraphicMemory) {
247 graphicMemory = &resources[i];
248 }
249 }
250
251 // first pass to handle secure/non-secure codec conflict
252 if (secureCodec != NULL) {
253 if (!mSupportsMultipleSecureCodecs) {
254 if (!getAllClients_l(callingPid, String8(kResourceSecureCodec), &clients)) {
255 return false;
256 }
257 }
258 if (!mSupportsSecureWithNonSecureCodec) {
259 if (!getAllClients_l(callingPid, String8(kResourceNonSecureCodec), &clients)) {
260 return false;
261 }
262 }
263 }
264 if (nonSecureCodec != NULL) {
265 if (!mSupportsSecureWithNonSecureCodec) {
266 if (!getAllClients_l(callingPid, String8(kResourceSecureCodec), &clients)) {
267 return false;
Ronghua Wu231c3d12015-03-11 15:10:32 -0700268 }
269 }
270 }
271
272 if (clients.size() == 0) {
273 // if no secure/non-secure codec conflict, run second pass to handle other resources.
Ronghua Wu05d89f12015-07-07 16:47:42 -0700274 getClientForResource_l(callingPid, graphicMemory, &clients);
Ronghua Wu231c3d12015-03-11 15:10:32 -0700275 }
Ronghua Wu67e7f542015-03-13 10:47:08 -0700276
277 if (clients.size() == 0) {
278 // if we are here, run the third pass to free one codec with the same type.
Ronghua Wu05d89f12015-07-07 16:47:42 -0700279 getClientForResource_l(callingPid, secureCodec, &clients);
280 getClientForResource_l(callingPid, nonSecureCodec, &clients);
281 }
282
283 if (clients.size() == 0) {
284 // if we are here, run the fourth pass to free one codec with the different type.
285 if (secureCodec != NULL) {
286 MediaResource temp(String8(kResourceNonSecureCodec), 1);
287 getClientForResource_l(callingPid, &temp, &clients);
288 }
289 if (nonSecureCodec != NULL) {
290 MediaResource temp(String8(kResourceSecureCodec), 1);
291 getClientForResource_l(callingPid, &temp, &clients);
Ronghua Wu67e7f542015-03-13 10:47:08 -0700292 }
293 }
Ronghua Wu231c3d12015-03-11 15:10:32 -0700294 }
295
296 if (clients.size() == 0) {
297 return false;
298 }
299
Ronghua Wu67e7f542015-03-13 10:47:08 -0700300 sp<IResourceManagerClient> failedClient;
Ronghua Wu231c3d12015-03-11 15:10:32 -0700301 for (size_t i = 0; i < clients.size(); ++i) {
Ronghua Wua8ec8fc2015-05-07 13:58:22 -0700302 log = String8::format("reclaimResource from client %p", clients[i].get());
303 mServiceLog->add(log);
Ronghua Wu231c3d12015-03-11 15:10:32 -0700304 if (!clients[i]->reclaimResource()) {
Ronghua Wu67e7f542015-03-13 10:47:08 -0700305 failedClient = clients[i];
306 break;
Ronghua Wu231c3d12015-03-11 15:10:32 -0700307 }
308 }
Ronghua Wu67e7f542015-03-13 10:47:08 -0700309
310 {
311 Mutex::Autolock lock(mLock);
312 bool found = false;
313 for (size_t i = 0; i < mMap.size(); ++i) {
314 ResourceInfos &infos = mMap.editValueAt(i);
315 for (size_t j = 0; j < infos.size();) {
316 if (infos[j].client == failedClient) {
317 j = infos.removeAt(j);
318 found = true;
319 } else {
320 ++j;
321 }
322 }
323 if (found) {
324 break;
325 }
326 }
327 if (!found) {
328 ALOGV("didn't find failed client");
329 }
330 }
331
332 return (failedClient == NULL);
Ronghua Wu231c3d12015-03-11 15:10:32 -0700333}
334
335bool ResourceManagerService::getAllClients_l(
336 int callingPid, const String8 &type, Vector<sp<IResourceManagerClient>> *clients) {
337 Vector<sp<IResourceManagerClient>> temp;
338 for (size_t i = 0; i < mMap.size(); ++i) {
339 ResourceInfos &infos = mMap.editValueAt(i);
340 for (size_t j = 0; j < infos.size(); ++j) {
341 if (hasResourceType(type, infos[j].resources)) {
342 if (!isCallingPriorityHigher_l(callingPid, mMap.keyAt(i))) {
343 // some higher/equal priority process owns the resource,
344 // this request can't be fulfilled.
345 ALOGE("getAllClients_l: can't reclaim resource %s from pid %d",
346 type.string(), mMap.keyAt(i));
347 return false;
348 }
349 temp.push_back(infos[j].client);
350 }
351 }
352 }
353 if (temp.size() == 0) {
354 ALOGV("getAllClients_l: didn't find any resource %s", type.string());
355 return true;
356 }
357 clients->appendVector(temp);
358 return true;
359}
360
361bool ResourceManagerService::getLowestPriorityBiggestClient_l(
362 int callingPid, const String8 &type, sp<IResourceManagerClient> *client) {
363 int lowestPriorityPid;
364 int lowestPriority;
365 int callingPriority;
366 if (!mProcessInfo->getPriority(callingPid, &callingPriority)) {
367 ALOGE("getLowestPriorityBiggestClient_l: can't get process priority for pid %d",
368 callingPid);
369 return false;
370 }
371 if (!getLowestPriorityPid_l(type, &lowestPriorityPid, &lowestPriority)) {
372 return false;
373 }
374 if (lowestPriority <= callingPriority) {
375 ALOGE("getLowestPriorityBiggestClient_l: lowest priority %d vs caller priority %d",
376 lowestPriority, callingPriority);
377 return false;
378 }
379
380 if (!getBiggestClient_l(lowestPriorityPid, type, client)) {
381 return false;
382 }
383 return true;
384}
385
386bool ResourceManagerService::getLowestPriorityPid_l(
387 const String8 &type, int *lowestPriorityPid, int *lowestPriority) {
388 int pid = -1;
389 int priority = -1;
390 for (size_t i = 0; i < mMap.size(); ++i) {
391 if (mMap.valueAt(i).size() == 0) {
392 // no client on this process.
393 continue;
394 }
395 if (!hasResourceType(type, mMap.valueAt(i))) {
396 // doesn't have the requested resource type
397 continue;
398 }
399 int tempPid = mMap.keyAt(i);
400 int tempPriority;
401 if (!mProcessInfo->getPriority(tempPid, &tempPriority)) {
402 ALOGV("getLowestPriorityPid_l: can't get priority of pid %d, skipped", tempPid);
403 // TODO: remove this pid from mMap?
404 continue;
405 }
406 if (pid == -1 || tempPriority > priority) {
407 // initial the value
408 pid = tempPid;
409 priority = tempPriority;
410 }
411 }
412 if (pid != -1) {
413 *lowestPriorityPid = pid;
414 *lowestPriority = priority;
415 }
416 return (pid != -1);
417}
418
419bool ResourceManagerService::isCallingPriorityHigher_l(int callingPid, int pid) {
420 int callingPidPriority;
421 if (!mProcessInfo->getPriority(callingPid, &callingPidPriority)) {
422 return false;
423 }
424
425 int priority;
426 if (!mProcessInfo->getPriority(pid, &priority)) {
427 return false;
428 }
429
430 return (callingPidPriority < priority);
431}
432
433bool ResourceManagerService::getBiggestClient_l(
434 int pid, const String8 &type, sp<IResourceManagerClient> *client) {
435 ssize_t index = mMap.indexOfKey(pid);
436 if (index < 0) {
437 ALOGE("getBiggestClient_l: can't find resource info for pid %d", pid);
438 return false;
439 }
440
441 sp<IResourceManagerClient> clientTemp;
442 uint64_t largestValue = 0;
443 const ResourceInfos &infos = mMap.valueAt(index);
444 for (size_t i = 0; i < infos.size(); ++i) {
445 Vector<MediaResource> resources = infos[i].resources;
446 for (size_t j = 0; j < resources.size(); ++j) {
447 if (resources[j].mType == type) {
448 if (resources[j].mValue > largestValue) {
449 largestValue = resources[j].mValue;
450 clientTemp = infos[i].client;
451 }
452 }
453 }
454 }
455
456 if (clientTemp == NULL) {
457 ALOGE("getBiggestClient_l: can't find resource type %s for pid %d", type.string(), pid);
458 return false;
459 }
460
461 *client = clientTemp;
462 return true;
463}
464
465} // namespace android