根据请求的资源,尝试从 优先级低于调用进程的进程 中回收资源。
这里的优先级从 processinfo 服务获取, 通过进程状态计算
- 应用调用 reclaimResource
接口:
| 1 2 3 4 5 6 7 8 9 10 11 | // frameworks/av/media/libmedia/aidl/android/media/IResourceManagerService.aidl     /**      * Tries to reclaim resource from processes with lower priority than the      * calling process according to the requested resources.      *      * @param callingPid pid of the calling process.      * @param resources an array of resources to be reclaimed.      *      * @return true if the reclaim was successful and false otherwise.      */     boolean reclaimResource(int callingPid, in MediaResourceParcel[] resources); | 
应用调用 reclaimResource 的流程
1.0 MediaCodec 调用 reclaimResource
| 1 2 3 4 5 6 7 8 9 10 11 | // frameworks/av/media/libstagefright/MediaCodec.cpp bool MediaCodec::ResourceManagerServiceProxy::reclaimResource(         const std::vector<MediaResourceParcel> &resources) {     Mutex::Autolock _l(mLock);     if (mService == NULL) {         return false;     }     bool success;     Status status = mService->reclaimResource(mPid, resources, &success);     return status.isOk() && success; } | 
在 init start configure 的时候会调用
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | status_t MediaCodec::init(const AString &name) {     ...     std::vector<MediaResourceParcel> resources;     resources.push_back(MediaResource::CodecResource(secureCodec, mIsVideo));     for (int i = 0; i <= kMaxRetry; ++i) {         if (i > 0) {             // Don't try to reclaim resource for the first time.             if (!mResourceManagerProxy->reclaimResource(resources)) {                 break;             }         }         sp<AMessage> response;         err = PostAndAwaitResponse(msg, &response);         if (!isResourceError(err)) {             break;         }     }     ... } status_t MediaCodec::configure(...) {     ...     std::vector<MediaResourceParcel> resources;     resources.push_back(MediaResource::CodecResource(mFlags & kFlagIsSecure, mIsVideo));     // Don't know the buffer size at this point, but it's fine to use 1 because     // the reclaimResource call doesn't consider the requester's buffer size for now.     resources.push_back(MediaResource::GraphicMemoryResource(1));     for (int i = 0; i <= kMaxRetry; ++i) {         if (i > 0) {             // Don't try to reclaim resource for the first time.             if (!mResourceManagerProxy->reclaimResource(resources)) {                 break;             }         }         ...     }     ... } status_t MediaCodec::start() {     sp<AMessage> msg = new AMessage(kWhatStart, this);     status_t err;     std::vector<MediaResourceParcel> resources;     resources.push_back(MediaResource::CodecResource(mFlags & kFlagIsSecure, mIsVideo));     // Don't know the buffer size at this point, but it's fine to use 1 because     // the reclaimResource call doesn't consider the requester's buffer size for now.     resources.push_back(MediaResource::GraphicMemoryResource(1));     for (int i = 0; i <= kMaxRetry; ++i) {         if (i > 0) {             // Don't try to reclaim resource for the first time.             if (!mResourceManagerProxy->reclaimResource(resources)) {                 break;             }             ...         sp<AMessage> response;         err = PostAndAwaitResponse(msg, &response);         if (!isResourceError(err)) {             break;         }     }     return err; } | 
2.0 ResourceManagerService::reclaimResource 找到适合释放的低优先级 IResourceManagerClient
被释放目标: 会优先找自己进程内相同类型的资源. 找不到, 就会找最低优先级的进程内的资源
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | // frameworks/av/services/mediaresourcemanager/ResourceManagerService.cpp Status ResourceManagerService::reclaimResource(         int32_t callingPid,         const std::vector<MediaResourceParcel>& resources,         bool* _aidl_return) {     String8 log = String8::format("reclaimResource(callingPid %d, resources %s)",             callingPid, getString(resources).string());     mServiceLog->add(log);     *_aidl_return = false;     Vector<std::shared_ptr<IResourceManagerClient>> clients;     {         Mutex::Autolock lock(mLock);         if (!mProcessInfo->isValidPid(callingPid)) {             ALOGE("Rejected reclaimResource call with invalid callingPid.");             return Status::fromServiceSpecificError(BAD_VALUE);         }         const MediaResourceParcel *secureCodec = NULL;         const MediaResourceParcel *nonSecureCodec = NULL;         const MediaResourceParcel *graphicMemory = NULL;         const MediaResourceParcel *drmSession = NULL;         // 找到需要回收的资源类型         for (size_t i = 0; i < resources.size(); ++i) {             MediaResource::Type type = resources[i].type;             if (resources[i].type == MediaResource::Type::kSecureCodec) {                 secureCodec = &resources[i];             } else if (type == MediaResource::Type::kNonSecureCodec) {                 nonSecureCodec = &resources[i];             } else if (type == MediaResource::Type::kGraphicMemory) {                 graphicMemory = &resources[i];             } else if (type == MediaResource::Type::kDrmSession) {                 drmSession = &resources[i];             }         }         // first pass to handle secure/non-secure codec conflict         if (secureCodec != NULL) {             if (!mSupportsMultipleSecureCodecs) {                 // 从 addResource 的 Client 中找到有相同类型, 并且优先级低于 callingPid 的 Client 见 2.1                 if (!getAllClients_l(callingPid, MediaResource::Type::kSecureCodec, &clients)) {                     return Status::ok();                 }             }             if (!mSupportsSecureWithNonSecureCodec) {                 if (!getAllClients_l(callingPid, MediaResource::Type::kNonSecureCodec, &clients)) {                     return Status::ok();                 }             }         }         if (nonSecureCodec != NULL) {             if (!mSupportsSecureWithNonSecureCodec) {                 if (!getAllClients_l(callingPid, MediaResource::Type::kSecureCodec, &clients)) {                     return Status::ok();                 }             }         }         // getClientForResource_l 用于 找到与 drmSession/graphicMemory 的 type 相同, 优先级最低的进程, MediaResourceParcel.value 最大的 clients         if (drmSession != NULL) {             getClientForResource_l(callingPid, drmSession, &clients);             if (clients.size() == 0) {                 return Status::ok();             }         }         if (clients.size() == 0) {             // if no secure/non-secure codec conflict, run second pass to handle other resources.             // 见 2.2             getClientForResource_l(callingPid, graphicMemory, &clients);         }         if (clients.size() == 0) {             // if we are here, run the third pass to free one codec with the same type.             getClientForResource_l(callingPid, secureCodec, &clients);             getClientForResource_l(callingPid, nonSecureCodec, &clients);         }         if (clients.size() == 0) {             // if we are here, run the fourth pass to free one codec with the different type.             if (secureCodec != NULL) {                 MediaResource temp(MediaResource::Type::kNonSecureCodec, 1);                 getClientForResource_l(callingPid, &temp, &clients);             }             if (nonSecureCodec != NULL) {                 MediaResource temp(MediaResource::Type::kSecureCodec, 1);                 getClientForResource_l(callingPid, &temp, &clients);             }         }     }     // 见 3.0     *_aidl_return = reclaimInternal(clients);     return Status::ok(); | 
2.1 ResourceManagerService::getAllClients_l
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | // frameworks/av/services/mediaresourcemanager/ResourceManagerService.cpp bool ResourceManagerService::getAllClients_l(         int callingPid, MediaResource::Type type,         Vector<std::shared_ptr<IResourceManagerClient>> *clients) {     Vector<std::shared_ptr<IResourceManagerClient>> temp;     for (size_t i = 0; i < mMap.size(); ++i) {         ResourceInfos &infos = mMap.editValueAt(i);         for (size_t j = 0; j < infos.size(); ++j) {             if (hasResourceType(type, infos[j].resources)) {// Resource 中是否有相同类型的资源                 if (!isCallingPriorityHigher_l(callingPid, mMap.keyAt(i))) {// 判断调用者的优先级是否更大                     // some higher/equal priority process owns the resource,                     // this request can't be fulfilled.                     ALOGE("getAllClients_l: can't reclaim resource %s from pid %d",                             asString(type), mMap.keyAt(i));                     return false;                 }                 temp.push_back(infos[j].client);// 返回这个 client             }         }     }     if (temp.size() == 0) {         ALOGV("getAllClients_l: didn't find any resource %s", asString(type));         return true;     }     clients->appendVector(temp);     return true; } | 
2.2 ResourceManagerService::getClientForResource_l
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | // frameworks/av/services/mediaresourcemanager/ResourceManagerService.cpp void ResourceManagerService::getClientForResource_l(         int callingPid, const MediaResourceParcel *res,         Vector<std::shared_ptr<IResourceManagerClient>> *clients) {     if (res == NULL) {         return;     }     std::shared_ptr<IResourceManagerClient> client;     if (getLowestPriorityBiggestClient_l(callingPid, res->type, &client)) {         clients->push_back(client);     } } // 找到最低优先级的进程, 拥有的 value 最大的那个 Client bool ResourceManagerService::getLowestPriorityBiggestClient_l(         int callingPid, MediaResource::Type type,         std::shared_ptr<IResourceManagerClient> *client) {     int lowestPriorityPid;     int lowestPriority;     int callingPriority;     // Before looking into other processes, check if we have clients marked for     // pending removal in the same process.     if (getBiggestClient_l(callingPid, type, client, true /* pendingRemovalOnly */)) {         return true;     }     // 见 2.3 getPriority_l     if (!getPriority_l(callingPid, &callingPriority)) {         ALOGE("getLowestPriorityBiggestClient_l: can't get process priority for pid %d",                 callingPid);         return false;     }     // 找到优先级最低的 pid, 以及它对应的优先级     if (!getLowestPriorityPid_l(type, &lowestPriorityPid, &lowestPriority)) {         return false;     }     if (lowestPriority <= callingPriority) {// 数字越大, 优先级越低. 确保找到的最低, 比 callingPid 也要低         ALOGE("getLowestPriorityBiggestClient_l: lowest priority %d vs caller priority %d",                 lowestPriority, callingPriority);         return false;     }     if (!getBiggestClient_l(lowestPriorityPid, type, client)) {// Resource 的 value 最大的 那个 Client         return false;     }     return true; } | 
2.3 ResourceManagerService::getPriority_l
| 1 2 3 4 5 6 7 8 9 10 11 12 | // frameworks/av/services/mediaresourcemanager/ResourceManagerService.cpp bool ResourceManagerService::getPriority_l(int pid, int* priority) {     int newPid = pid;     if (mOverridePidMap.find(pid) != mOverridePidMap.end()) {         newPid = mOverridePidMap[pid];         ALOGD("getPriority_l: use override pid %d instead original pid %d",                 newPid, pid);     }     return mProcessInfo->getPriority(newPid, priority); } | 
2.4 ProcessInfo::getPriority
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | // frameworks/av/media/utils/ProcessInfo.cpp bool ProcessInfo::getPriority(int pid, int* priority) {     sp<IBinder> binder = defaultServiceManager()->getService(String16("processinfo"));     sp<IProcessInfoService> service = interface_cast<IProcessInfoService>(binder);     size_t length = 1;     int32_t state;     static const int32_t INVALID_ADJ = -10000;     static const int32_t NATIVE_ADJ = -1000;     int32_t score = INVALID_ADJ;     // 对应的 service 在 ActivityManagerService     status_t err = service->getProcessStatesAndOomScoresFromPids(length, &pid, &state, &score);     if (err != OK) {         ALOGE("getProcessStatesAndOomScoresFromPids failed");         return false;     }     ALOGV("pid %d state %d score %d", pid, state, score);     if (score <= NATIVE_ADJ) {         ALOGE("pid %d invalid OOM adjustments value %d", pid, score);         return false;     }     // Use OOM adjustments value as the priority. Lower the value, higher the priority.     *priority = score;     return true; } | 
3.0 调用 IResourceManagerClient 的 reclaimResource
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | // frameworks/av/services/mediaresourcemanager/ResourceManagerService.cpp bool ResourceManagerService::reclaimInternal(         const Vector<std::shared_ptr<IResourceManagerClient>> &clients) {     if (clients.size() == 0) {         return false;     }     std::shared_ptr<IResourceManagerClient> failedClient;     for (size_t i = 0; i < clients.size(); ++i) {         String8 log = String8::format("reclaimResource from client %p", clients[i].get());         mServiceLog->add(log);         bool success;         // 见 4.0         Status status = clients[i]->reclaimResource(&success);// 调用对应 MediaCodec 中的 reclaimResource         if (!status.isOk() || !success) {             failedClient = clients[i];             break;         }     }     if (failedClient == NULL) {         return true;     }     ...     return false; } | 
4.0 IResourceManagerClient.reclaimResource
以 MediaCodec 为例
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | // frameworks/av/media/libstagefright/MediaCodec.cpp struct ResourceManagerClient : public BnResourceManagerClient {     explicit ResourceManagerClient(MediaCodec* codec) : mMediaCodec(codec) {}     Status reclaimResource(bool* _aidl_return) override {         sp<MediaCodec> codec = mMediaCodec.promote();         if (codec == NULL) {             // codec is already gone.             *_aidl_return = true;             return Status::ok();         }         status_t err = codec->reclaim();// 见 5.0         if (err == WOULD_BLOCK) {             ALOGD("Wait for the client to release codec.");             usleep(kMaxReclaimWaitTimeInUs);             ALOGD("Try to reclaim again.");             err = codec->reclaim(true /* force */);         }         if (err != OK) {             ALOGW("ResourceManagerClient failed to release codec with err %d", err);         }         *_aidl_return = (err == OK);         return Status::ok();     }     ... } | 
5.0 MediaCodec::reclaim
触发处理 kWhatRelease 事件
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | // frameworks/av/media/libstagefright/MediaCodec.cpp status_t MediaCodec::reclaim(bool force) {     ALOGD("MediaCodec::reclaim(%p) %s", this, mInitName.c_str());     sp<AMessage> msg = new AMessage(kWhatRelease, this);     msg->setInt32("reclaimed", 1);     msg->setInt32("force", force ? 1 : 0);     sp<AMessage> response;     status_t ret = PostAndAwaitResponse(msg, &response);     if (ret == -ENOENT) {         ALOGD("MediaCodec looper is gone, skip reclaim");         ret = OK;     }     return ret; } | 
6.0 MediaCodec kWhatRelease 事件处理
| 1 2 | // frameworks/av/media/libstagefright/MediaCodec.cpp 见其他文章 | 
 
	
0 Comments