blob: 4f998608b4337ff7269d351662fc3d938fd63408 [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
Dongwon Kangfe508d32015-12-15 14:22:05 +090022#include <binder/IMediaResourceMonitor.h>
Ronghua Wu231c3d12015-03-11 15:10:32 -070023#include <binder/IServiceManager.h>
24#include <dirent.h>
25#include <media/stagefright/ProcessInfo.h>
26#include <string.h>
27#include <sys/types.h>
28#include <sys/stat.h>
29#include <sys/time.h>
30#include <unistd.h>
31
32#include "ResourceManagerService.h"
Ronghua Wua8ec8fc2015-05-07 13:58:22 -070033#include "ServiceLog.h"
Ronghua Wu231c3d12015-03-11 15:10:32 -070034
35namespace android {
36
37template <typename T>
38static String8 getString(const Vector<T> &items) {
39 String8 itemsStr;
40 for (size_t i = 0; i < items.size(); ++i) {
41 itemsStr.appendFormat("%s ", items[i].toString().string());
42 }
43 return itemsStr;
44}
45
46static bool hasResourceType(String8 type, Vector<MediaResource> resources) {
47 for (size_t i = 0; i < resources.size(); ++i) {
48 if (resources[i].mType == type) {
49 return true;
50 }
51 }
52 return false;
53}
54
55static bool hasResourceType(String8 type, ResourceInfos infos) {
56 for (size_t i = 0; i < infos.size(); ++i) {
57 if (hasResourceType(type, infos[i].resources)) {
58 return true;
59 }
60 }
61 return false;
62}
63
64static ResourceInfos& getResourceInfosForEdit(
65 int pid,
66 PidResourceInfosMap& map) {
67 ssize_t index = map.indexOfKey(pid);
68 if (index < 0) {
69 // new pid
70 ResourceInfos infosForPid;
71 map.add(pid, infosForPid);
72 }
73
74 return map.editValueFor(pid);
75}
76
77static ResourceInfo& getResourceInfoForEdit(
78 int64_t clientId,
79 const sp<IResourceManagerClient> client,
80 ResourceInfos& infos) {
81 for (size_t i = 0; i < infos.size(); ++i) {
82 if (infos[i].clientId == clientId) {
83 return infos.editItemAt(i);
84 }
85 }
86 ResourceInfo info;
87 info.clientId = clientId;
88 info.client = client;
89 infos.push_back(info);
90 return infos.editItemAt(infos.size() - 1);
91}
92
Dongwon Kangfe508d32015-12-15 14:22:05 +090093static void notifyResourceGranted(int pid, const Vector<MediaResource> &resources) {
94 static const char* const kServiceName = "media_resource_monitor";
95 sp<IBinder> binder = defaultServiceManager()->getService(String16(kServiceName));
96 if (binder != NULL) {
97 sp<IMediaResourceMonitor> service = interface_cast<IMediaResourceMonitor>(binder);
98 for (size_t i = 0; i < resources.size(); ++i) {
99 service->notifyResourceGranted(pid, String16(resources[i].mType),
100 String16(resources[i].mSubType), resources[i].mValue);
101 }
102 }
103}
104
Ronghua Wua8ec8fc2015-05-07 13:58:22 -0700105status_t ResourceManagerService::dump(int fd, const Vector<String16>& /* args */) {
Ronghua Wu8f9dd872015-04-23 15:24:25 -0700106 String8 result;
Ronghua Wu8f9dd872015-04-23 15:24:25 -0700107
dcashman014e91e2015-09-11 09:33:01 -0700108 if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
109 result.format("Permission Denial: "
110 "can't dump ResourceManagerService from pid=%d, uid=%d\n",
111 IPCThreadState::self()->getCallingPid(),
112 IPCThreadState::self()->getCallingUid());
113 write(fd, result.string(), result.size());
114 return PERMISSION_DENIED;
115 }
116
Ronghua Wu76d4c7f2015-10-23 15:01:53 -0700117 PidResourceInfosMap mapCopy;
118 bool supportsMultipleSecureCodecs;
119 bool supportsSecureWithNonSecureCodec;
120 String8 serviceLog;
121 {
122 Mutex::Autolock lock(mLock);
123 mapCopy = mMap; // Shadow copy, real copy will happen on write.
124 supportsMultipleSecureCodecs = mSupportsMultipleSecureCodecs;
125 supportsSecureWithNonSecureCodec = mSupportsSecureWithNonSecureCodec;
126 serviceLog = mServiceLog->toString(" " /* linePrefix */);
127 }
128
129 const size_t SIZE = 256;
130 char buffer[SIZE];
Ronghua Wu8f9dd872015-04-23 15:24:25 -0700131 snprintf(buffer, SIZE, "ResourceManagerService: %p\n", this);
132 result.append(buffer);
133 result.append(" Policies:\n");
Ronghua Wu76d4c7f2015-10-23 15:01:53 -0700134 snprintf(buffer, SIZE, " SupportsMultipleSecureCodecs: %d\n", supportsMultipleSecureCodecs);
Ronghua Wu8f9dd872015-04-23 15:24:25 -0700135 result.append(buffer);
Ronghua Wu76d4c7f2015-10-23 15:01:53 -0700136 snprintf(buffer, SIZE, " SupportsSecureWithNonSecureCodec: %d\n",
137 supportsSecureWithNonSecureCodec);
Ronghua Wu8f9dd872015-04-23 15:24:25 -0700138 result.append(buffer);
139
Ronghua Wua8ec8fc2015-05-07 13:58:22 -0700140 result.append(" Processes:\n");
Ronghua Wu76d4c7f2015-10-23 15:01:53 -0700141 for (size_t i = 0; i < mapCopy.size(); ++i) {
142 snprintf(buffer, SIZE, " Pid: %d\n", mapCopy.keyAt(i));
Ronghua Wu8f9dd872015-04-23 15:24:25 -0700143 result.append(buffer);
144
Ronghua Wu76d4c7f2015-10-23 15:01:53 -0700145 const ResourceInfos &infos = mapCopy.valueAt(i);
Ronghua Wu8f9dd872015-04-23 15:24:25 -0700146 for (size_t j = 0; j < infos.size(); ++j) {
Ronghua Wua8ec8fc2015-05-07 13:58:22 -0700147 result.append(" Client:\n");
Ronghua Wu8f9dd872015-04-23 15:24:25 -0700148 snprintf(buffer, SIZE, " Id: %lld\n", (long long)infos[j].clientId);
149 result.append(buffer);
150
151 snprintf(buffer, SIZE, " Name: %s\n", infos[j].client->getName().string());
152 result.append(buffer);
153
154 Vector<MediaResource> resources = infos[j].resources;
Ronghua Wua8ec8fc2015-05-07 13:58:22 -0700155 result.append(" Resources:\n");
Ronghua Wu8f9dd872015-04-23 15:24:25 -0700156 for (size_t k = 0; k < resources.size(); ++k) {
157 snprintf(buffer, SIZE, " %s\n", resources[k].toString().string());
158 result.append(buffer);
159 }
160 }
161 }
Ronghua Wu022ed722015-05-11 15:15:09 -0700162 result.append(" Events logs (most recent at top):\n");
Ronghua Wu76d4c7f2015-10-23 15:01:53 -0700163 result.append(serviceLog);
Ronghua Wu8f9dd872015-04-23 15:24:25 -0700164
165 write(fd, result.string(), result.size());
166 return OK;
167}
168
Ronghua Wu231c3d12015-03-11 15:10:32 -0700169ResourceManagerService::ResourceManagerService()
170 : mProcessInfo(new ProcessInfo()),
Ronghua Wua8ec8fc2015-05-07 13:58:22 -0700171 mServiceLog(new ServiceLog()),
Ronghua Wu231c3d12015-03-11 15:10:32 -0700172 mSupportsMultipleSecureCodecs(true),
173 mSupportsSecureWithNonSecureCodec(true) {}
174
175ResourceManagerService::ResourceManagerService(sp<ProcessInfoInterface> processInfo)
176 : mProcessInfo(processInfo),
Ronghua Wua8ec8fc2015-05-07 13:58:22 -0700177 mServiceLog(new ServiceLog()),
Ronghua Wu231c3d12015-03-11 15:10:32 -0700178 mSupportsMultipleSecureCodecs(true),
179 mSupportsSecureWithNonSecureCodec(true) {}
180
181ResourceManagerService::~ResourceManagerService() {}
182
183void ResourceManagerService::config(const Vector<MediaResourcePolicy> &policies) {
Ronghua Wua8ec8fc2015-05-07 13:58:22 -0700184 String8 log = String8::format("config(%s)", getString(policies).string());
185 mServiceLog->add(log);
Ronghua Wu231c3d12015-03-11 15:10:32 -0700186
187 Mutex::Autolock lock(mLock);
188 for (size_t i = 0; i < policies.size(); ++i) {
189 String8 type = policies[i].mType;
Ronghua Wu9ba21b92015-04-21 14:23:06 -0700190 String8 value = policies[i].mValue;
Ronghua Wu231c3d12015-03-11 15:10:32 -0700191 if (type == kPolicySupportsMultipleSecureCodecs) {
Ronghua Wu9ba21b92015-04-21 14:23:06 -0700192 mSupportsMultipleSecureCodecs = (value == "true");
Ronghua Wu231c3d12015-03-11 15:10:32 -0700193 } else if (type == kPolicySupportsSecureWithNonSecureCodec) {
Ronghua Wu9ba21b92015-04-21 14:23:06 -0700194 mSupportsSecureWithNonSecureCodec = (value == "true");
Ronghua Wu231c3d12015-03-11 15:10:32 -0700195 }
196 }
197}
198
199void ResourceManagerService::addResource(
200 int pid,
201 int64_t clientId,
202 const sp<IResourceManagerClient> client,
203 const Vector<MediaResource> &resources) {
Ronghua Wua8ec8fc2015-05-07 13:58:22 -0700204 String8 log = String8::format("addResource(pid %d, clientId %lld, resources %s)",
Ronghua Wu231c3d12015-03-11 15:10:32 -0700205 pid, (long long) clientId, getString(resources).string());
Ronghua Wua8ec8fc2015-05-07 13:58:22 -0700206 mServiceLog->add(log);
Ronghua Wu231c3d12015-03-11 15:10:32 -0700207
208 Mutex::Autolock lock(mLock);
209 ResourceInfos& infos = getResourceInfosForEdit(pid, mMap);
210 ResourceInfo& info = getResourceInfoForEdit(clientId, client, infos);
Ronghua Wu67e7f542015-03-13 10:47:08 -0700211 // TODO: do the merge instead of append.
Ronghua Wu231c3d12015-03-11 15:10:32 -0700212 info.resources.appendVector(resources);
Dongwon Kangfe508d32015-12-15 14:22:05 +0900213 notifyResourceGranted(pid, resources);
Ronghua Wu231c3d12015-03-11 15:10:32 -0700214}
215
Ronghua Wu37c89242015-07-15 12:23:48 -0700216void ResourceManagerService::removeResource(int pid, int64_t clientId) {
217 String8 log = String8::format(
218 "removeResource(pid %d, clientId %lld)",
219 pid, (long long) clientId);
Ronghua Wua8ec8fc2015-05-07 13:58:22 -0700220 mServiceLog->add(log);
Ronghua Wu231c3d12015-03-11 15:10:32 -0700221
222 Mutex::Autolock lock(mLock);
Ronghua Wu37c89242015-07-15 12:23:48 -0700223 ssize_t index = mMap.indexOfKey(pid);
224 if (index < 0) {
225 ALOGV("removeResource: didn't find pid %d for clientId %lld", pid, (long long) clientId);
226 return;
227 }
Ronghua Wu231c3d12015-03-11 15:10:32 -0700228 bool found = false;
Ronghua Wu37c89242015-07-15 12:23:48 -0700229 ResourceInfos &infos = mMap.editValueAt(index);
230 for (size_t j = 0; j < infos.size(); ++j) {
231 if (infos[j].clientId == clientId) {
232 j = infos.removeAt(j);
233 found = true;
Ronghua Wu231c3d12015-03-11 15:10:32 -0700234 break;
235 }
236 }
237 if (!found) {
238 ALOGV("didn't find client");
239 }
240}
241
Ronghua Wu05d89f12015-07-07 16:47:42 -0700242void ResourceManagerService::getClientForResource_l(
243 int callingPid, const MediaResource *res, Vector<sp<IResourceManagerClient>> *clients) {
244 if (res == NULL) {
245 return;
246 }
247 sp<IResourceManagerClient> client;
248 if (getLowestPriorityBiggestClient_l(callingPid, res->mType, &client)) {
249 clients->push_back(client);
250 }
251}
252
Ronghua Wu231c3d12015-03-11 15:10:32 -0700253bool ResourceManagerService::reclaimResource(
254 int callingPid, const Vector<MediaResource> &resources) {
Ronghua Wua8ec8fc2015-05-07 13:58:22 -0700255 String8 log = String8::format("reclaimResource(callingPid %d, resources %s)",
Ronghua Wu231c3d12015-03-11 15:10:32 -0700256 callingPid, getString(resources).string());
Ronghua Wua8ec8fc2015-05-07 13:58:22 -0700257 mServiceLog->add(log);
Ronghua Wu231c3d12015-03-11 15:10:32 -0700258
259 Vector<sp<IResourceManagerClient>> clients;
260 {
261 Mutex::Autolock lock(mLock);
Ronghua Wu05d89f12015-07-07 16:47:42 -0700262 const MediaResource *secureCodec = NULL;
263 const MediaResource *nonSecureCodec = NULL;
264 const MediaResource *graphicMemory = NULL;
Ronghua Wu231c3d12015-03-11 15:10:32 -0700265 for (size_t i = 0; i < resources.size(); ++i) {
266 String8 type = resources[i].mType;
Ronghua Wu05d89f12015-07-07 16:47:42 -0700267 if (resources[i].mType == kResourceSecureCodec) {
268 secureCodec = &resources[i];
Ronghua Wu231c3d12015-03-11 15:10:32 -0700269 } else if (type == kResourceNonSecureCodec) {
Ronghua Wu05d89f12015-07-07 16:47:42 -0700270 nonSecureCodec = &resources[i];
271 } else if (type == kResourceGraphicMemory) {
272 graphicMemory = &resources[i];
273 }
274 }
275
276 // first pass to handle secure/non-secure codec conflict
277 if (secureCodec != NULL) {
278 if (!mSupportsMultipleSecureCodecs) {
279 if (!getAllClients_l(callingPid, String8(kResourceSecureCodec), &clients)) {
280 return false;
281 }
282 }
283 if (!mSupportsSecureWithNonSecureCodec) {
284 if (!getAllClients_l(callingPid, String8(kResourceNonSecureCodec), &clients)) {
285 return false;
286 }
287 }
288 }
289 if (nonSecureCodec != NULL) {
290 if (!mSupportsSecureWithNonSecureCodec) {
291 if (!getAllClients_l(callingPid, String8(kResourceSecureCodec), &clients)) {
292 return false;
Ronghua Wu231c3d12015-03-11 15:10:32 -0700293 }
294 }
295 }
296
297 if (clients.size() == 0) {
298 // if no secure/non-secure codec conflict, run second pass to handle other resources.
Ronghua Wu05d89f12015-07-07 16:47:42 -0700299 getClientForResource_l(callingPid, graphicMemory, &clients);
Ronghua Wu231c3d12015-03-11 15:10:32 -0700300 }
Ronghua Wu67e7f542015-03-13 10:47:08 -0700301
302 if (clients.size() == 0) {
303 // if we are here, run the third pass to free one codec with the same type.
Ronghua Wu05d89f12015-07-07 16:47:42 -0700304 getClientForResource_l(callingPid, secureCodec, &clients);
305 getClientForResource_l(callingPid, nonSecureCodec, &clients);
306 }
307
308 if (clients.size() == 0) {
309 // if we are here, run the fourth pass to free one codec with the different type.
310 if (secureCodec != NULL) {
311 MediaResource temp(String8(kResourceNonSecureCodec), 1);
312 getClientForResource_l(callingPid, &temp, &clients);
313 }
314 if (nonSecureCodec != NULL) {
315 MediaResource temp(String8(kResourceSecureCodec), 1);
316 getClientForResource_l(callingPid, &temp, &clients);
Ronghua Wu67e7f542015-03-13 10:47:08 -0700317 }
318 }
Ronghua Wu231c3d12015-03-11 15:10:32 -0700319 }
320
321 if (clients.size() == 0) {
322 return false;
323 }
324
Ronghua Wu67e7f542015-03-13 10:47:08 -0700325 sp<IResourceManagerClient> failedClient;
Ronghua Wu231c3d12015-03-11 15:10:32 -0700326 for (size_t i = 0; i < clients.size(); ++i) {
Ronghua Wua8ec8fc2015-05-07 13:58:22 -0700327 log = String8::format("reclaimResource from client %p", clients[i].get());
328 mServiceLog->add(log);
Ronghua Wu231c3d12015-03-11 15:10:32 -0700329 if (!clients[i]->reclaimResource()) {
Ronghua Wu67e7f542015-03-13 10:47:08 -0700330 failedClient = clients[i];
331 break;
Ronghua Wu231c3d12015-03-11 15:10:32 -0700332 }
333 }
Ronghua Wu67e7f542015-03-13 10:47:08 -0700334
Ronghua Wu76d4c7f2015-10-23 15:01:53 -0700335 if (failedClient == NULL) {
336 return true;
337 }
338
Ronghua Wu67e7f542015-03-13 10:47:08 -0700339 {
340 Mutex::Autolock lock(mLock);
341 bool found = false;
342 for (size_t i = 0; i < mMap.size(); ++i) {
343 ResourceInfos &infos = mMap.editValueAt(i);
344 for (size_t j = 0; j < infos.size();) {
345 if (infos[j].client == failedClient) {
346 j = infos.removeAt(j);
347 found = true;
348 } else {
349 ++j;
350 }
351 }
352 if (found) {
353 break;
354 }
355 }
356 if (!found) {
357 ALOGV("didn't find failed client");
358 }
359 }
360
Ronghua Wu76d4c7f2015-10-23 15:01:53 -0700361 return false;
Ronghua Wu231c3d12015-03-11 15:10:32 -0700362}
363
364bool ResourceManagerService::getAllClients_l(
365 int callingPid, const String8 &type, Vector<sp<IResourceManagerClient>> *clients) {
366 Vector<sp<IResourceManagerClient>> temp;
367 for (size_t i = 0; i < mMap.size(); ++i) {
368 ResourceInfos &infos = mMap.editValueAt(i);
369 for (size_t j = 0; j < infos.size(); ++j) {
370 if (hasResourceType(type, infos[j].resources)) {
371 if (!isCallingPriorityHigher_l(callingPid, mMap.keyAt(i))) {
372 // some higher/equal priority process owns the resource,
373 // this request can't be fulfilled.
374 ALOGE("getAllClients_l: can't reclaim resource %s from pid %d",
375 type.string(), mMap.keyAt(i));
376 return false;
377 }
378 temp.push_back(infos[j].client);
379 }
380 }
381 }
382 if (temp.size() == 0) {
383 ALOGV("getAllClients_l: didn't find any resource %s", type.string());
384 return true;
385 }
386 clients->appendVector(temp);
387 return true;
388}
389
390bool ResourceManagerService::getLowestPriorityBiggestClient_l(
391 int callingPid, const String8 &type, sp<IResourceManagerClient> *client) {
392 int lowestPriorityPid;
393 int lowestPriority;
394 int callingPriority;
395 if (!mProcessInfo->getPriority(callingPid, &callingPriority)) {
396 ALOGE("getLowestPriorityBiggestClient_l: can't get process priority for pid %d",
397 callingPid);
398 return false;
399 }
400 if (!getLowestPriorityPid_l(type, &lowestPriorityPid, &lowestPriority)) {
401 return false;
402 }
403 if (lowestPriority <= callingPriority) {
404 ALOGE("getLowestPriorityBiggestClient_l: lowest priority %d vs caller priority %d",
405 lowestPriority, callingPriority);
406 return false;
407 }
408
409 if (!getBiggestClient_l(lowestPriorityPid, type, client)) {
410 return false;
411 }
412 return true;
413}
414
415bool ResourceManagerService::getLowestPriorityPid_l(
416 const String8 &type, int *lowestPriorityPid, int *lowestPriority) {
417 int pid = -1;
418 int priority = -1;
419 for (size_t i = 0; i < mMap.size(); ++i) {
420 if (mMap.valueAt(i).size() == 0) {
421 // no client on this process.
422 continue;
423 }
424 if (!hasResourceType(type, mMap.valueAt(i))) {
425 // doesn't have the requested resource type
426 continue;
427 }
428 int tempPid = mMap.keyAt(i);
429 int tempPriority;
430 if (!mProcessInfo->getPriority(tempPid, &tempPriority)) {
431 ALOGV("getLowestPriorityPid_l: can't get priority of pid %d, skipped", tempPid);
432 // TODO: remove this pid from mMap?
433 continue;
434 }
435 if (pid == -1 || tempPriority > priority) {
436 // initial the value
437 pid = tempPid;
438 priority = tempPriority;
439 }
440 }
441 if (pid != -1) {
442 *lowestPriorityPid = pid;
443 *lowestPriority = priority;
444 }
445 return (pid != -1);
446}
447
448bool ResourceManagerService::isCallingPriorityHigher_l(int callingPid, int pid) {
449 int callingPidPriority;
450 if (!mProcessInfo->getPriority(callingPid, &callingPidPriority)) {
451 return false;
452 }
453
454 int priority;
455 if (!mProcessInfo->getPriority(pid, &priority)) {
456 return false;
457 }
458
459 return (callingPidPriority < priority);
460}
461
462bool ResourceManagerService::getBiggestClient_l(
463 int pid, const String8 &type, sp<IResourceManagerClient> *client) {
464 ssize_t index = mMap.indexOfKey(pid);
465 if (index < 0) {
466 ALOGE("getBiggestClient_l: can't find resource info for pid %d", pid);
467 return false;
468 }
469
470 sp<IResourceManagerClient> clientTemp;
471 uint64_t largestValue = 0;
472 const ResourceInfos &infos = mMap.valueAt(index);
473 for (size_t i = 0; i < infos.size(); ++i) {
474 Vector<MediaResource> resources = infos[i].resources;
475 for (size_t j = 0; j < resources.size(); ++j) {
476 if (resources[j].mType == type) {
477 if (resources[j].mValue > largestValue) {
478 largestValue = resources[j].mValue;
479 clientTemp = infos[i].client;
480 }
481 }
482 }
483 }
484
485 if (clientTemp == NULL) {
486 ALOGE("getBiggestClient_l: can't find resource type %s for pid %d", type.string(), pid);
487 return false;
488 }
489
490 *client = clientTemp;
491 return true;
492}
493
494} // namespace android