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/IMediaResourceMonitor.h>
23 #include <binder/IServiceManager.h>
24 #include <cutils/sched_policy.h>
25 #include <dirent.h>
26 #include <media/stagefright/ProcessInfo.h>
27 #include <mediautils/BatteryNotifier.h>
28 #include <mediautils/SchedulingPolicyService.h>
29 #include <string.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <sys/time.h>
33 #include <unistd.h>
34 
35 #include "ResourceManagerService.h"
36 #include "ServiceLog.h"
37 
38 namespace android {
39 
40 namespace {
41 
42 class DeathNotifier : public IBinder::DeathRecipient {
43 public:
DeathNotifier(const wp<ResourceManagerService> & service,int pid,int64_t clientId)44     DeathNotifier(const wp<ResourceManagerService> &service, int pid, int64_t clientId)
45         : mService(service), mPid(pid), mClientId(clientId) {}
46 
binderDied(const wp<IBinder> &)47     virtual void binderDied(const wp<IBinder> & /* who */) override {
48         // Don't check for pid validity since we know it's already dead.
49         sp<ResourceManagerService> service = mService.promote();
50         if (service == nullptr) {
51             ALOGW("ResourceManagerService is dead as well.");
52             return;
53         }
54         service->removeResource(mPid, mClientId, false);
55     }
56 
57 private:
58     wp<ResourceManagerService> mService;
59     int mPid;
60     int64_t mClientId;
61 };
62 
63 }  // namespace
64 
65 template <typename T>
getString(const Vector<T> & items)66 static String8 getString(const Vector<T> &items) {
67     String8 itemsStr;
68     for (size_t i = 0; i < items.size(); ++i) {
69         itemsStr.appendFormat("%s ", items[i].toString().string());
70     }
71     return itemsStr;
72 }
73 
hasResourceType(MediaResource::Type type,const ResourceList & resources)74 static bool hasResourceType(MediaResource::Type type, const ResourceList& resources) {
75     for (auto it = resources.begin(); it != resources.end(); it++) {
76         if (it->second.mType == type) {
77             return true;
78         }
79     }
80     return false;
81 }
82 
hasResourceType(MediaResource::Type type,const ResourceInfos & infos)83 static bool hasResourceType(MediaResource::Type type, const ResourceInfos& infos) {
84     for (size_t i = 0; i < infos.size(); ++i) {
85         if (hasResourceType(type, infos[i].resources)) {
86             return true;
87         }
88     }
89     return false;
90 }
91 
getResourceInfosForEdit(int pid,PidResourceInfosMap & map)92 static ResourceInfos& getResourceInfosForEdit(
93         int pid,
94         PidResourceInfosMap& map) {
95     ssize_t index = map.indexOfKey(pid);
96     if (index < 0) {
97         // new pid
98         ResourceInfos infosForPid;
99         map.add(pid, infosForPid);
100     }
101 
102     return map.editValueFor(pid);
103 }
104 
getResourceInfoForEdit(uid_t uid,int64_t clientId,const sp<IResourceManagerClient> & client,ResourceInfos & infos)105 static ResourceInfo& getResourceInfoForEdit(
106         uid_t uid,
107         int64_t clientId,
108         const sp<IResourceManagerClient>& client,
109         ResourceInfos& infos) {
110     ssize_t index = infos.indexOfKey(clientId);
111 
112     if (index < 0) {
113         ResourceInfo info;
114         info.uid = uid;
115         info.clientId = clientId;
116         info.client = client;
117 
118         index = infos.add(clientId, info);
119     }
120 
121     return infos.editValueAt(index);
122 }
123 
notifyResourceGranted(int pid,const Vector<MediaResource> & resources)124 static void notifyResourceGranted(int pid, const Vector<MediaResource> &resources) {
125     static const char* const kServiceName = "media_resource_monitor";
126     sp<IBinder> binder = defaultServiceManager()->checkService(String16(kServiceName));
127     if (binder != NULL) {
128         sp<IMediaResourceMonitor> service = interface_cast<IMediaResourceMonitor>(binder);
129         for (size_t i = 0; i < resources.size(); ++i) {
130             if (resources[i].mSubType == MediaResource::kAudioCodec) {
131                 service->notifyResourceGranted(pid, IMediaResourceMonitor::TYPE_AUDIO_CODEC);
132             } else if (resources[i].mSubType == MediaResource::kVideoCodec) {
133                 service->notifyResourceGranted(pid, IMediaResourceMonitor::TYPE_VIDEO_CODEC);
134             }
135         }
136     }
137 }
138 
dump(int fd,const Vector<String16> &)139 status_t ResourceManagerService::dump(int fd, const Vector<String16>& /* args */) {
140     String8 result;
141 
142     if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
143         result.format("Permission Denial: "
144                 "can't dump ResourceManagerService from pid=%d, uid=%d\n",
145                 IPCThreadState::self()->getCallingPid(),
146                 IPCThreadState::self()->getCallingUid());
147         write(fd, result.string(), result.size());
148         return PERMISSION_DENIED;
149     }
150 
151     PidResourceInfosMap mapCopy;
152     bool supportsMultipleSecureCodecs;
153     bool supportsSecureWithNonSecureCodec;
154     String8 serviceLog;
155     {
156         Mutex::Autolock lock(mLock);
157         mapCopy = mMap;  // Shadow copy, real copy will happen on write.
158         supportsMultipleSecureCodecs = mSupportsMultipleSecureCodecs;
159         supportsSecureWithNonSecureCodec = mSupportsSecureWithNonSecureCodec;
160         serviceLog = mServiceLog->toString("    " /* linePrefix */);
161     }
162 
163     const size_t SIZE = 256;
164     char buffer[SIZE];
165     snprintf(buffer, SIZE, "ResourceManagerService: %p\n", this);
166     result.append(buffer);
167     result.append("  Policies:\n");
168     snprintf(buffer, SIZE, "    SupportsMultipleSecureCodecs: %d\n", supportsMultipleSecureCodecs);
169     result.append(buffer);
170     snprintf(buffer, SIZE, "    SupportsSecureWithNonSecureCodec: %d\n",
171             supportsSecureWithNonSecureCodec);
172     result.append(buffer);
173 
174     result.append("  Processes:\n");
175     for (size_t i = 0; i < mapCopy.size(); ++i) {
176         snprintf(buffer, SIZE, "    Pid: %d\n", mapCopy.keyAt(i));
177         result.append(buffer);
178 
179         const ResourceInfos &infos = mapCopy.valueAt(i);
180         for (size_t j = 0; j < infos.size(); ++j) {
181             result.append("      Client:\n");
182             snprintf(buffer, SIZE, "        Id: %lld\n", (long long)infos[j].clientId);
183             result.append(buffer);
184 
185             snprintf(buffer, SIZE, "        Name: %s\n", infos[j].client->getName().string());
186             result.append(buffer);
187 
188             const ResourceList &resources = infos[j].resources;
189             result.append("        Resources:\n");
190             for (auto it = resources.begin(); it != resources.end(); it++) {
191                 snprintf(buffer, SIZE, "          %s\n", it->second.toString().string());
192                 result.append(buffer);
193             }
194         }
195     }
196     result.append("  Events logs (most recent at top):\n");
197     result.append(serviceLog);
198 
199     write(fd, result.string(), result.size());
200     return OK;
201 }
202 
203 struct SystemCallbackImpl :
204         public ResourceManagerService::SystemCallbackInterface {
SystemCallbackImplandroid::SystemCallbackImpl205     SystemCallbackImpl() {}
206 
noteStartVideoandroid::SystemCallbackImpl207     virtual void noteStartVideo(int uid) override {
208         BatteryNotifier::getInstance().noteStartVideo(uid);
209     }
noteStopVideoandroid::SystemCallbackImpl210     virtual void noteStopVideo(int uid) override {
211         BatteryNotifier::getInstance().noteStopVideo(uid);
212     }
noteResetVideoandroid::SystemCallbackImpl213     virtual void noteResetVideo() override {
214         BatteryNotifier::getInstance().noteResetVideo();
215     }
requestCpusetBoostandroid::SystemCallbackImpl216     virtual bool requestCpusetBoost(
217             bool enable, const sp<IInterface> &client) override {
218         return android::requestCpusetBoost(enable, client);
219     }
220 
221 protected:
~SystemCallbackImplandroid::SystemCallbackImpl222     virtual ~SystemCallbackImpl() {}
223 
224 private:
225     DISALLOW_EVIL_CONSTRUCTORS(SystemCallbackImpl);
226 };
227 
ResourceManagerService()228 ResourceManagerService::ResourceManagerService()
229     : ResourceManagerService(new ProcessInfo(), new SystemCallbackImpl()) {}
230 
ResourceManagerService(const sp<ProcessInfoInterface> & processInfo,const sp<SystemCallbackInterface> & systemResource)231 ResourceManagerService::ResourceManagerService(
232         const sp<ProcessInfoInterface> &processInfo,
233         const sp<SystemCallbackInterface> &systemResource)
234     : mProcessInfo(processInfo),
235       mSystemCB(systemResource),
236       mServiceLog(new ServiceLog()),
237       mSupportsMultipleSecureCodecs(true),
238       mSupportsSecureWithNonSecureCodec(true),
239       mCpuBoostCount(0) {
240     mSystemCB->noteResetVideo();
241 }
242 
~ResourceManagerService()243 ResourceManagerService::~ResourceManagerService() {}
244 
config(const Vector<MediaResourcePolicy> & policies)245 void ResourceManagerService::config(const Vector<MediaResourcePolicy> &policies) {
246     String8 log = String8::format("config(%s)", getString(policies).string());
247     mServiceLog->add(log);
248 
249     Mutex::Autolock lock(mLock);
250     for (size_t i = 0; i < policies.size(); ++i) {
251         String8 type = policies[i].mType;
252         String8 value = policies[i].mValue;
253         if (type == kPolicySupportsMultipleSecureCodecs) {
254             mSupportsMultipleSecureCodecs = (value == "true");
255         } else if (type == kPolicySupportsSecureWithNonSecureCodec) {
256             mSupportsSecureWithNonSecureCodec = (value == "true");
257         }
258     }
259 }
260 
onFirstAdded(const MediaResource & resource,const ResourceInfo & clientInfo)261 void ResourceManagerService::onFirstAdded(
262         const MediaResource& resource, const ResourceInfo& clientInfo) {
263     // first time added
264     if (resource.mType == MediaResource::kCpuBoost
265      && resource.mSubType == MediaResource::kUnspecifiedSubType) {
266         // Request it on every new instance of kCpuBoost, as the media.codec
267         // could have died, if we only do it the first time subsequent instances
268         // never gets the boost.
269         if (mSystemCB->requestCpusetBoost(true, this) != OK) {
270             ALOGW("couldn't request cpuset boost");
271         }
272         mCpuBoostCount++;
273     } else if (resource.mType == MediaResource::kBattery
274             && resource.mSubType == MediaResource::kVideoCodec) {
275         mSystemCB->noteStartVideo(clientInfo.uid);
276     }
277 }
278 
onLastRemoved(const MediaResource & resource,const ResourceInfo & clientInfo)279 void ResourceManagerService::onLastRemoved(
280         const MediaResource& resource, const ResourceInfo& clientInfo) {
281     if (resource.mType == MediaResource::kCpuBoost
282             && resource.mSubType == MediaResource::kUnspecifiedSubType
283             && mCpuBoostCount > 0) {
284         if (--mCpuBoostCount == 0) {
285             mSystemCB->requestCpusetBoost(false, this);
286         }
287     } else if (resource.mType == MediaResource::kBattery
288             && resource.mSubType == MediaResource::kVideoCodec) {
289         mSystemCB->noteStopVideo(clientInfo.uid);
290     }
291 }
292 
mergeResources(MediaResource & r1,const MediaResource & r2)293 void ResourceManagerService::mergeResources(
294         MediaResource& r1, const MediaResource& r2) {
295     if (r1.mType == MediaResource::kDrmSession) {
296         // This means we are using a session. Each session's mValue is initialized to UINT64_MAX.
297         // The oftener a session is used the lower it's mValue. During reclaim the session with
298         // the highest mValue/lowest usage would be closed.
299         r1.mValue -= (r1.mValue == 0 ? 0 : 1);
300     } else {
301         r1.mValue += r2.mValue;
302     }
303 }
304 
addResource(int pid,int uid,int64_t clientId,const sp<IResourceManagerClient> client,const Vector<MediaResource> & resources)305 void ResourceManagerService::addResource(
306         int pid,
307         int uid,
308         int64_t clientId,
309         const sp<IResourceManagerClient> client,
310         const Vector<MediaResource> &resources) {
311     String8 log = String8::format("addResource(pid %d, clientId %lld, resources %s)",
312             pid, (long long) clientId, getString(resources).string());
313     mServiceLog->add(log);
314 
315     Mutex::Autolock lock(mLock);
316     if (!mProcessInfo->isValidPid(pid)) {
317         ALOGE("Rejected addResource call with invalid pid.");
318         return;
319     }
320     ResourceInfos& infos = getResourceInfosForEdit(pid, mMap);
321     ResourceInfo& info = getResourceInfoForEdit(uid, clientId, client, infos);
322 
323     for (size_t i = 0; i < resources.size(); ++i) {
324         const auto &res = resources[i];
325         const auto resType = std::tuple(res.mType, res.mSubType, res.mId);
326         if (info.resources.find(resType) == info.resources.end()) {
327             onFirstAdded(res, info);
328             info.resources[resType] = res;
329         } else {
330             mergeResources(info.resources[resType], res);
331         }
332     }
333     if (info.deathNotifier == nullptr && client != nullptr) {
334         info.deathNotifier = new DeathNotifier(this, pid, clientId);
335         IInterface::asBinder(client)->linkToDeath(info.deathNotifier);
336     }
337     notifyResourceGranted(pid, resources);
338 }
339 
removeResource(int pid,int64_t clientId,const Vector<MediaResource> & resources)340 void ResourceManagerService::removeResource(int pid, int64_t clientId,
341         const Vector<MediaResource> &resources) {
342     String8 log = String8::format("removeResource(pid %d, clientId %lld, resources %s)",
343             pid, (long long) clientId, getString(resources).string());
344     mServiceLog->add(log);
345 
346     Mutex::Autolock lock(mLock);
347     if (!mProcessInfo->isValidPid(pid)) {
348         ALOGE("Rejected removeResource call with invalid pid.");
349         return;
350     }
351     ssize_t index = mMap.indexOfKey(pid);
352     if (index < 0) {
353         ALOGV("removeResource: didn't find pid %d for clientId %lld", pid, (long long) clientId);
354         return;
355     }
356     ResourceInfos &infos = mMap.editValueAt(index);
357 
358     index = infos.indexOfKey(clientId);
359     if (index < 0) {
360         ALOGV("removeResource: didn't find clientId %lld", (long long) clientId);
361         return;
362     }
363 
364     ResourceInfo &info = infos.editValueAt(index);
365 
366     for (size_t i = 0; i < resources.size(); ++i) {
367         const auto &res = resources[i];
368         const auto resType = std::tuple(res.mType, res.mSubType, res.mId);
369         // ignore if we don't have it
370         if (info.resources.find(resType) != info.resources.end()) {
371             MediaResource &resource = info.resources[resType];
372             if (resource.mValue > res.mValue) {
373                 resource.mValue -= res.mValue;
374             } else {
375                 // drm sessions always take this branch because res.mValue is set
376                 // to UINT64_MAX
377                 onLastRemoved(res, info);
378                 info.resources.erase(resType);
379             }
380         }
381     }
382 }
383 
removeClient(int pid,int64_t clientId)384 void ResourceManagerService::removeClient(int pid, int64_t clientId) {
385     removeResource(pid, clientId, true);
386 }
387 
removeResource(int pid,int64_t clientId,bool checkValid)388 void ResourceManagerService::removeResource(int pid, int64_t clientId, bool checkValid) {
389     String8 log = String8::format(
390             "removeResource(pid %d, clientId %lld)",
391             pid, (long long) clientId);
392     mServiceLog->add(log);
393 
394     Mutex::Autolock lock(mLock);
395     if (checkValid && !mProcessInfo->isValidPid(pid)) {
396         ALOGE("Rejected removeResource call with invalid pid.");
397         return;
398     }
399     ssize_t index = mMap.indexOfKey(pid);
400     if (index < 0) {
401         ALOGV("removeResource: didn't find pid %d for clientId %lld", pid, (long long) clientId);
402         return;
403     }
404     ResourceInfos &infos = mMap.editValueAt(index);
405 
406     index = infos.indexOfKey(clientId);
407     if (index < 0) {
408         ALOGV("removeResource: didn't find clientId %lld", (long long) clientId);
409         return;
410     }
411 
412     const ResourceInfo &info = infos[index];
413     for (auto it = info.resources.begin(); it != info.resources.end(); it++) {
414         onLastRemoved(it->second, info);
415     }
416 
417     IInterface::asBinder(info.client)->unlinkToDeath(info.deathNotifier);
418 
419     infos.removeItemsAt(index);
420 }
421 
getClientForResource_l(int callingPid,const MediaResource * res,Vector<sp<IResourceManagerClient>> * clients)422 void ResourceManagerService::getClientForResource_l(
423         int callingPid, const MediaResource *res, Vector<sp<IResourceManagerClient>> *clients) {
424     if (res == NULL) {
425         return;
426     }
427     sp<IResourceManagerClient> client;
428     if (getLowestPriorityBiggestClient_l(callingPid, res->mType, &client)) {
429         clients->push_back(client);
430     }
431 }
432 
reclaimResource(int callingPid,const Vector<MediaResource> & resources)433 bool ResourceManagerService::reclaimResource(
434         int callingPid, const Vector<MediaResource> &resources) {
435     String8 log = String8::format("reclaimResource(callingPid %d, resources %s)",
436             callingPid, getString(resources).string());
437     mServiceLog->add(log);
438 
439     Vector<sp<IResourceManagerClient>> clients;
440     {
441         Mutex::Autolock lock(mLock);
442         if (!mProcessInfo->isValidPid(callingPid)) {
443             ALOGE("Rejected reclaimResource call with invalid callingPid.");
444             return false;
445         }
446         const MediaResource *secureCodec = NULL;
447         const MediaResource *nonSecureCodec = NULL;
448         const MediaResource *graphicMemory = NULL;
449         const MediaResource *drmSession = NULL;
450         for (size_t i = 0; i < resources.size(); ++i) {
451             MediaResource::Type type = resources[i].mType;
452             if (resources[i].mType == MediaResource::kSecureCodec) {
453                 secureCodec = &resources[i];
454             } else if (type == MediaResource::kNonSecureCodec) {
455                 nonSecureCodec = &resources[i];
456             } else if (type == MediaResource::kGraphicMemory) {
457                 graphicMemory = &resources[i];
458             } else if (type == MediaResource::kDrmSession) {
459                 drmSession = &resources[i];
460             }
461         }
462 
463         // first pass to handle secure/non-secure codec conflict
464         if (secureCodec != NULL) {
465             if (!mSupportsMultipleSecureCodecs) {
466                 if (!getAllClients_l(callingPid, MediaResource::kSecureCodec, &clients)) {
467                     return false;
468                 }
469             }
470             if (!mSupportsSecureWithNonSecureCodec) {
471                 if (!getAllClients_l(callingPid, MediaResource::kNonSecureCodec, &clients)) {
472                     return false;
473                 }
474             }
475         }
476         if (nonSecureCodec != NULL) {
477             if (!mSupportsSecureWithNonSecureCodec) {
478                 if (!getAllClients_l(callingPid, MediaResource::kSecureCodec, &clients)) {
479                     return false;
480                 }
481             }
482         }
483         if (drmSession != NULL) {
484             getClientForResource_l(callingPid, drmSession, &clients);
485             if (clients.size() == 0) {
486                 return false;
487             }
488         }
489 
490         if (clients.size() == 0) {
491             // if no secure/non-secure codec conflict, run second pass to handle other resources.
492             getClientForResource_l(callingPid, graphicMemory, &clients);
493         }
494 
495         if (clients.size() == 0) {
496             // if we are here, run the third pass to free one codec with the same type.
497             getClientForResource_l(callingPid, secureCodec, &clients);
498             getClientForResource_l(callingPid, nonSecureCodec, &clients);
499         }
500 
501         if (clients.size() == 0) {
502             // if we are here, run the fourth pass to free one codec with the different type.
503             if (secureCodec != NULL) {
504                 MediaResource temp(MediaResource::kNonSecureCodec, 1);
505                 getClientForResource_l(callingPid, &temp, &clients);
506             }
507             if (nonSecureCodec != NULL) {
508                 MediaResource temp(MediaResource::kSecureCodec, 1);
509                 getClientForResource_l(callingPid, &temp, &clients);
510             }
511         }
512     }
513 
514     if (clients.size() == 0) {
515         return false;
516     }
517 
518     sp<IResourceManagerClient> failedClient;
519     for (size_t i = 0; i < clients.size(); ++i) {
520         log = String8::format("reclaimResource from client %p", clients[i].get());
521         mServiceLog->add(log);
522         if (!clients[i]->reclaimResource()) {
523             failedClient = clients[i];
524             break;
525         }
526     }
527 
528     if (failedClient == NULL) {
529         return true;
530     }
531 
532     {
533         Mutex::Autolock lock(mLock);
534         bool found = false;
535         for (size_t i = 0; i < mMap.size(); ++i) {
536             ResourceInfos &infos = mMap.editValueAt(i);
537             for (size_t j = 0; j < infos.size();) {
538                 if (infos[j].client == failedClient) {
539                     j = infos.removeItemsAt(j);
540                     found = true;
541                 } else {
542                     ++j;
543                 }
544             }
545             if (found) {
546                 break;
547             }
548         }
549         if (!found) {
550             ALOGV("didn't find failed client");
551         }
552     }
553 
554     return false;
555 }
556 
getAllClients_l(int callingPid,MediaResource::Type type,Vector<sp<IResourceManagerClient>> * clients)557 bool ResourceManagerService::getAllClients_l(
558         int callingPid, MediaResource::Type type, Vector<sp<IResourceManagerClient>> *clients) {
559     Vector<sp<IResourceManagerClient>> temp;
560     for (size_t i = 0; i < mMap.size(); ++i) {
561         ResourceInfos &infos = mMap.editValueAt(i);
562         for (size_t j = 0; j < infos.size(); ++j) {
563             if (hasResourceType(type, infos[j].resources)) {
564                 if (!isCallingPriorityHigher_l(callingPid, mMap.keyAt(i))) {
565                     // some higher/equal priority process owns the resource,
566                     // this request can't be fulfilled.
567                     ALOGE("getAllClients_l: can't reclaim resource %s from pid %d",
568                             asString(type), mMap.keyAt(i));
569                     return false;
570                 }
571                 temp.push_back(infos[j].client);
572             }
573         }
574     }
575     if (temp.size() == 0) {
576         ALOGV("getAllClients_l: didn't find any resource %s", asString(type));
577         return true;
578     }
579     clients->appendVector(temp);
580     return true;
581 }
582 
getLowestPriorityBiggestClient_l(int callingPid,MediaResource::Type type,sp<IResourceManagerClient> * client)583 bool ResourceManagerService::getLowestPriorityBiggestClient_l(
584         int callingPid, MediaResource::Type type, sp<IResourceManagerClient> *client) {
585     int lowestPriorityPid;
586     int lowestPriority;
587     int callingPriority;
588     if (!mProcessInfo->getPriority(callingPid, &callingPriority)) {
589         ALOGE("getLowestPriorityBiggestClient_l: can't get process priority for pid %d",
590                 callingPid);
591         return false;
592     }
593     if (!getLowestPriorityPid_l(type, &lowestPriorityPid, &lowestPriority)) {
594         return false;
595     }
596     if (lowestPriority <= callingPriority) {
597         ALOGE("getLowestPriorityBiggestClient_l: lowest priority %d vs caller priority %d",
598                 lowestPriority, callingPriority);
599         return false;
600     }
601 
602     if (!getBiggestClient_l(lowestPriorityPid, type, client)) {
603         return false;
604     }
605     return true;
606 }
607 
getLowestPriorityPid_l(MediaResource::Type type,int * lowestPriorityPid,int * lowestPriority)608 bool ResourceManagerService::getLowestPriorityPid_l(
609         MediaResource::Type type, int *lowestPriorityPid, int *lowestPriority) {
610     int pid = -1;
611     int priority = -1;
612     for (size_t i = 0; i < mMap.size(); ++i) {
613         if (mMap.valueAt(i).size() == 0) {
614             // no client on this process.
615             continue;
616         }
617         if (!hasResourceType(type, mMap.valueAt(i))) {
618             // doesn't have the requested resource type
619             continue;
620         }
621         int tempPid = mMap.keyAt(i);
622         int tempPriority;
623         if (!mProcessInfo->getPriority(tempPid, &tempPriority)) {
624             ALOGV("getLowestPriorityPid_l: can't get priority of pid %d, skipped", tempPid);
625             // TODO: remove this pid from mMap?
626             continue;
627         }
628         if (pid == -1 || tempPriority > priority) {
629             // initial the value
630             pid = tempPid;
631             priority = tempPriority;
632         }
633     }
634     if (pid != -1) {
635         *lowestPriorityPid = pid;
636         *lowestPriority = priority;
637     }
638     return (pid != -1);
639 }
640 
isCallingPriorityHigher_l(int callingPid,int pid)641 bool ResourceManagerService::isCallingPriorityHigher_l(int callingPid, int pid) {
642     int callingPidPriority;
643     if (!mProcessInfo->getPriority(callingPid, &callingPidPriority)) {
644         return false;
645     }
646 
647     int priority;
648     if (!mProcessInfo->getPriority(pid, &priority)) {
649         return false;
650     }
651 
652     return (callingPidPriority < priority);
653 }
654 
getBiggestClient_l(int pid,MediaResource::Type type,sp<IResourceManagerClient> * client)655 bool ResourceManagerService::getBiggestClient_l(
656         int pid, MediaResource::Type type, sp<IResourceManagerClient> *client) {
657     ssize_t index = mMap.indexOfKey(pid);
658     if (index < 0) {
659         ALOGE("getBiggestClient_l: can't find resource info for pid %d", pid);
660         return false;
661     }
662 
663     sp<IResourceManagerClient> clientTemp;
664     uint64_t largestValue = 0;
665     const ResourceInfos &infos = mMap.valueAt(index);
666     for (size_t i = 0; i < infos.size(); ++i) {
667         const ResourceList &resources = infos[i].resources;
668         for (auto it = resources.begin(); it != resources.end(); it++) {
669             const MediaResource &resource = it->second;
670             if (resource.mType == type) {
671                 if (resource.mValue > largestValue) {
672                     largestValue = resource.mValue;
673                     clientTemp = infos[i].client;
674                 }
675             }
676         }
677     }
678 
679     if (clientTemp == NULL) {
680         ALOGE("getBiggestClient_l: can't find resource type %s for pid %d", asString(type), pid);
681         return false;
682     }
683 
684     *client = clientTemp;
685     return true;
686 }
687 
688 } // namespace android
689