根据请求的资源,尝试从 优先级低于调用进程的进程 中回收资源。
这里的优先级从 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