1 /*
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"
32 #include "ServiceLog.h"
33
34 namespace android {
35
36 template <typename T>
getString(const Vector<T> & items)37 static 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
hasResourceType(String8 type,Vector<MediaResource> resources)45 static 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
hasResourceType(String8 type,ResourceInfos infos)54 static 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
getResourceInfosForEdit(int pid,PidResourceInfosMap & map)63 static 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
getResourceInfoForEdit(int64_t clientId,const sp<IResourceManagerClient> client,ResourceInfos & infos)76 static 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
dump(int fd,const Vector<String16> &)92 status_t ResourceManagerService::dump(int fd, const Vector<String16>& /* args */) {
93 Mutex::Autolock lock(mLock);
94
95 String8 result;
96 const size_t SIZE = 256;
97 char buffer[SIZE];
98
99 snprintf(buffer, SIZE, "ResourceManagerService: %p\n", this);
100 result.append(buffer);
101 result.append(" Policies:\n");
102 snprintf(buffer, SIZE, " SupportsMultipleSecureCodecs: %d\n", mSupportsMultipleSecureCodecs);
103 result.append(buffer);
104 snprintf(buffer, SIZE, " SupportsSecureWithNonSecureCodec: %d\n", mSupportsSecureWithNonSecureCodec);
105 result.append(buffer);
106
107 result.append(" Processes:\n");
108 for (size_t i = 0; i < mMap.size(); ++i) {
109 snprintf(buffer, SIZE, " Pid: %d\n", mMap.keyAt(i));
110 result.append(buffer);
111
112 const ResourceInfos &infos = mMap.valueAt(i);
113 for (size_t j = 0; j < infos.size(); ++j) {
114 result.append(" Client:\n");
115 snprintf(buffer, SIZE, " Id: %lld\n", (long long)infos[j].clientId);
116 result.append(buffer);
117
118 snprintf(buffer, SIZE, " Name: %s\n", infos[j].client->getName().string());
119 result.append(buffer);
120
121 Vector<MediaResource> resources = infos[j].resources;
122 result.append(" Resources:\n");
123 for (size_t k = 0; k < resources.size(); ++k) {
124 snprintf(buffer, SIZE, " %s\n", resources[k].toString().string());
125 result.append(buffer);
126 }
127 }
128 }
129 result.append(" Events logs (most recent at top):\n");
130 result.append(mServiceLog->toString(" " /* linePrefix */));
131
132 write(fd, result.string(), result.size());
133 return OK;
134 }
135
ResourceManagerService()136 ResourceManagerService::ResourceManagerService()
137 : mProcessInfo(new ProcessInfo()),
138 mServiceLog(new ServiceLog()),
139 mSupportsMultipleSecureCodecs(true),
140 mSupportsSecureWithNonSecureCodec(true) {}
141
ResourceManagerService(sp<ProcessInfoInterface> processInfo)142 ResourceManagerService::ResourceManagerService(sp<ProcessInfoInterface> processInfo)
143 : mProcessInfo(processInfo),
144 mServiceLog(new ServiceLog()),
145 mSupportsMultipleSecureCodecs(true),
146 mSupportsSecureWithNonSecureCodec(true) {}
147
~ResourceManagerService()148 ResourceManagerService::~ResourceManagerService() {}
149
config(const Vector<MediaResourcePolicy> & policies)150 void ResourceManagerService::config(const Vector<MediaResourcePolicy> &policies) {
151 String8 log = String8::format("config(%s)", getString(policies).string());
152 mServiceLog->add(log);
153
154 Mutex::Autolock lock(mLock);
155 for (size_t i = 0; i < policies.size(); ++i) {
156 String8 type = policies[i].mType;
157 String8 value = policies[i].mValue;
158 if (type == kPolicySupportsMultipleSecureCodecs) {
159 mSupportsMultipleSecureCodecs = (value == "true");
160 } else if (type == kPolicySupportsSecureWithNonSecureCodec) {
161 mSupportsSecureWithNonSecureCodec = (value == "true");
162 }
163 }
164 }
165
addResource(int pid,int64_t clientId,const sp<IResourceManagerClient> client,const Vector<MediaResource> & resources)166 void ResourceManagerService::addResource(
167 int pid,
168 int64_t clientId,
169 const sp<IResourceManagerClient> client,
170 const Vector<MediaResource> &resources) {
171 String8 log = String8::format("addResource(pid %d, clientId %lld, resources %s)",
172 pid, (long long) clientId, getString(resources).string());
173 mServiceLog->add(log);
174
175 Mutex::Autolock lock(mLock);
176 ResourceInfos& infos = getResourceInfosForEdit(pid, mMap);
177 ResourceInfo& info = getResourceInfoForEdit(clientId, client, infos);
178 // TODO: do the merge instead of append.
179 info.resources.appendVector(resources);
180 }
181
removeResource(int pid,int64_t clientId)182 void ResourceManagerService::removeResource(int pid, int64_t clientId) {
183 String8 log = String8::format(
184 "removeResource(pid %d, clientId %lld)",
185 pid, (long long) clientId);
186 mServiceLog->add(log);
187
188 Mutex::Autolock lock(mLock);
189 ssize_t index = mMap.indexOfKey(pid);
190 if (index < 0) {
191 ALOGV("removeResource: didn't find pid %d for clientId %lld", pid, (long long) clientId);
192 return;
193 }
194 bool found = false;
195 ResourceInfos &infos = mMap.editValueAt(index);
196 for (size_t j = 0; j < infos.size(); ++j) {
197 if (infos[j].clientId == clientId) {
198 j = infos.removeAt(j);
199 found = true;
200 break;
201 }
202 }
203 if (!found) {
204 ALOGV("didn't find client");
205 }
206 }
207
getClientForResource_l(int callingPid,const MediaResource * res,Vector<sp<IResourceManagerClient>> * clients)208 void ResourceManagerService::getClientForResource_l(
209 int callingPid, const MediaResource *res, Vector<sp<IResourceManagerClient>> *clients) {
210 if (res == NULL) {
211 return;
212 }
213 sp<IResourceManagerClient> client;
214 if (getLowestPriorityBiggestClient_l(callingPid, res->mType, &client)) {
215 clients->push_back(client);
216 }
217 }
218
reclaimResource(int callingPid,const Vector<MediaResource> & resources)219 bool ResourceManagerService::reclaimResource(
220 int callingPid, const Vector<MediaResource> &resources) {
221 String8 log = String8::format("reclaimResource(callingPid %d, resources %s)",
222 callingPid, getString(resources).string());
223 mServiceLog->add(log);
224
225 Vector<sp<IResourceManagerClient>> clients;
226 {
227 Mutex::Autolock lock(mLock);
228 const MediaResource *secureCodec = NULL;
229 const MediaResource *nonSecureCodec = NULL;
230 const MediaResource *graphicMemory = NULL;
231 for (size_t i = 0; i < resources.size(); ++i) {
232 String8 type = resources[i].mType;
233 if (resources[i].mType == kResourceSecureCodec) {
234 secureCodec = &resources[i];
235 } else if (type == kResourceNonSecureCodec) {
236 nonSecureCodec = &resources[i];
237 } else if (type == kResourceGraphicMemory) {
238 graphicMemory = &resources[i];
239 }
240 }
241
242 // first pass to handle secure/non-secure codec conflict
243 if (secureCodec != NULL) {
244 if (!mSupportsMultipleSecureCodecs) {
245 if (!getAllClients_l(callingPid, String8(kResourceSecureCodec), &clients)) {
246 return false;
247 }
248 }
249 if (!mSupportsSecureWithNonSecureCodec) {
250 if (!getAllClients_l(callingPid, String8(kResourceNonSecureCodec), &clients)) {
251 return false;
252 }
253 }
254 }
255 if (nonSecureCodec != NULL) {
256 if (!mSupportsSecureWithNonSecureCodec) {
257 if (!getAllClients_l(callingPid, String8(kResourceSecureCodec), &clients)) {
258 return false;
259 }
260 }
261 }
262
263 if (clients.size() == 0) {
264 // if no secure/non-secure codec conflict, run second pass to handle other resources.
265 getClientForResource_l(callingPid, graphicMemory, &clients);
266 }
267
268 if (clients.size() == 0) {
269 // if we are here, run the third pass to free one codec with the same type.
270 getClientForResource_l(callingPid, secureCodec, &clients);
271 getClientForResource_l(callingPid, nonSecureCodec, &clients);
272 }
273
274 if (clients.size() == 0) {
275 // if we are here, run the fourth pass to free one codec with the different type.
276 if (secureCodec != NULL) {
277 MediaResource temp(String8(kResourceNonSecureCodec), 1);
278 getClientForResource_l(callingPid, &temp, &clients);
279 }
280 if (nonSecureCodec != NULL) {
281 MediaResource temp(String8(kResourceSecureCodec), 1);
282 getClientForResource_l(callingPid, &temp, &clients);
283 }
284 }
285 }
286
287 if (clients.size() == 0) {
288 return false;
289 }
290
291 sp<IResourceManagerClient> failedClient;
292 for (size_t i = 0; i < clients.size(); ++i) {
293 log = String8::format("reclaimResource from client %p", clients[i].get());
294 mServiceLog->add(log);
295 if (!clients[i]->reclaimResource()) {
296 failedClient = clients[i];
297 break;
298 }
299 }
300
301 {
302 Mutex::Autolock lock(mLock);
303 bool found = false;
304 for (size_t i = 0; i < mMap.size(); ++i) {
305 ResourceInfos &infos = mMap.editValueAt(i);
306 for (size_t j = 0; j < infos.size();) {
307 if (infos[j].client == failedClient) {
308 j = infos.removeAt(j);
309 found = true;
310 } else {
311 ++j;
312 }
313 }
314 if (found) {
315 break;
316 }
317 }
318 if (!found) {
319 ALOGV("didn't find failed client");
320 }
321 }
322
323 return (failedClient == NULL);
324 }
325
getAllClients_l(int callingPid,const String8 & type,Vector<sp<IResourceManagerClient>> * clients)326 bool ResourceManagerService::getAllClients_l(
327 int callingPid, const String8 &type, Vector<sp<IResourceManagerClient>> *clients) {
328 Vector<sp<IResourceManagerClient>> temp;
329 for (size_t i = 0; i < mMap.size(); ++i) {
330 ResourceInfos &infos = mMap.editValueAt(i);
331 for (size_t j = 0; j < infos.size(); ++j) {
332 if (hasResourceType(type, infos[j].resources)) {
333 if (!isCallingPriorityHigher_l(callingPid, mMap.keyAt(i))) {
334 // some higher/equal priority process owns the resource,
335 // this request can't be fulfilled.
336 ALOGE("getAllClients_l: can't reclaim resource %s from pid %d",
337 type.string(), mMap.keyAt(i));
338 return false;
339 }
340 temp.push_back(infos[j].client);
341 }
342 }
343 }
344 if (temp.size() == 0) {
345 ALOGV("getAllClients_l: didn't find any resource %s", type.string());
346 return true;
347 }
348 clients->appendVector(temp);
349 return true;
350 }
351
getLowestPriorityBiggestClient_l(int callingPid,const String8 & type,sp<IResourceManagerClient> * client)352 bool ResourceManagerService::getLowestPriorityBiggestClient_l(
353 int callingPid, const String8 &type, sp<IResourceManagerClient> *client) {
354 int lowestPriorityPid;
355 int lowestPriority;
356 int callingPriority;
357 if (!mProcessInfo->getPriority(callingPid, &callingPriority)) {
358 ALOGE("getLowestPriorityBiggestClient_l: can't get process priority for pid %d",
359 callingPid);
360 return false;
361 }
362 if (!getLowestPriorityPid_l(type, &lowestPriorityPid, &lowestPriority)) {
363 return false;
364 }
365 if (lowestPriority <= callingPriority) {
366 ALOGE("getLowestPriorityBiggestClient_l: lowest priority %d vs caller priority %d",
367 lowestPriority, callingPriority);
368 return false;
369 }
370
371 if (!getBiggestClient_l(lowestPriorityPid, type, client)) {
372 return false;
373 }
374 return true;
375 }
376
getLowestPriorityPid_l(const String8 & type,int * lowestPriorityPid,int * lowestPriority)377 bool ResourceManagerService::getLowestPriorityPid_l(
378 const String8 &type, int *lowestPriorityPid, int *lowestPriority) {
379 int pid = -1;
380 int priority = -1;
381 for (size_t i = 0; i < mMap.size(); ++i) {
382 if (mMap.valueAt(i).size() == 0) {
383 // no client on this process.
384 continue;
385 }
386 if (!hasResourceType(type, mMap.valueAt(i))) {
387 // doesn't have the requested resource type
388 continue;
389 }
390 int tempPid = mMap.keyAt(i);
391 int tempPriority;
392 if (!mProcessInfo->getPriority(tempPid, &tempPriority)) {
393 ALOGV("getLowestPriorityPid_l: can't get priority of pid %d, skipped", tempPid);
394 // TODO: remove this pid from mMap?
395 continue;
396 }
397 if (pid == -1 || tempPriority > priority) {
398 // initial the value
399 pid = tempPid;
400 priority = tempPriority;
401 }
402 }
403 if (pid != -1) {
404 *lowestPriorityPid = pid;
405 *lowestPriority = priority;
406 }
407 return (pid != -1);
408 }
409
isCallingPriorityHigher_l(int callingPid,int pid)410 bool ResourceManagerService::isCallingPriorityHigher_l(int callingPid, int pid) {
411 int callingPidPriority;
412 if (!mProcessInfo->getPriority(callingPid, &callingPidPriority)) {
413 return false;
414 }
415
416 int priority;
417 if (!mProcessInfo->getPriority(pid, &priority)) {
418 return false;
419 }
420
421 return (callingPidPriority < priority);
422 }
423
getBiggestClient_l(int pid,const String8 & type,sp<IResourceManagerClient> * client)424 bool ResourceManagerService::getBiggestClient_l(
425 int pid, const String8 &type, sp<IResourceManagerClient> *client) {
426 ssize_t index = mMap.indexOfKey(pid);
427 if (index < 0) {
428 ALOGE("getBiggestClient_l: can't find resource info for pid %d", pid);
429 return false;
430 }
431
432 sp<IResourceManagerClient> clientTemp;
433 uint64_t largestValue = 0;
434 const ResourceInfos &infos = mMap.valueAt(index);
435 for (size_t i = 0; i < infos.size(); ++i) {
436 Vector<MediaResource> resources = infos[i].resources;
437 for (size_t j = 0; j < resources.size(); ++j) {
438 if (resources[j].mType == type) {
439 if (resources[j].mValue > largestValue) {
440 largestValue = resources[j].mValue;
441 clientTemp = infos[i].client;
442 }
443 }
444 }
445 }
446
447 if (clientTemp == NULL) {
448 ALOGE("getBiggestClient_l: can't find resource type %s for pid %d", type.string(), pid);
449 return false;
450 }
451
452 *client = clientTemp;
453 return true;
454 }
455
456 } // namespace android
457