Loading media/libmediaplayerservice/tests/DrmSessionManager_test.cpp +2 −2 Original line number Original line Diff line number Diff line Loading @@ -148,8 +148,8 @@ static const std::vector<uint8_t> kTestSessionId3{9, 0}; class DrmSessionManagerTest : public ::testing::Test { class DrmSessionManagerTest : public ::testing::Test { public: public: DrmSessionManagerTest() DrmSessionManagerTest() : mService(::ndk::SharedRefBase::make<ResourceManagerService> : mService(ResourceManagerService::Create( (new FakeProcessInfo(), new FakeSystemCallback())), new FakeProcessInfo(), new FakeSystemCallback())), mDrmSessionManager(new DrmSessionManager(mService)), mDrmSessionManager(new DrmSessionManager(mService)), mTestDrm1(::ndk::SharedRefBase::make<FakeDrm>( mTestDrm1(::ndk::SharedRefBase::make<FakeDrm>( kTestSessionId1, mDrmSessionManager)), kTestSessionId1, mDrmSessionManager)), Loading services/mediaresourcemanager/ResourceManagerService.cpp +87 −230 Original line number Original line Diff line number Diff line Loading @@ -24,169 +24,19 @@ #include <binder/IPCThreadState.h> #include <binder/IPCThreadState.h> #include <binder/IServiceManager.h> #include <binder/IServiceManager.h> #include <cutils/sched_policy.h> #include <cutils/sched_policy.h> #include <dirent.h> #include <media/MediaResourcePolicy.h> #include <media/MediaResourcePolicy.h> #include <media/stagefright/foundation/ABase.h> #include <media/stagefright/foundation/ABase.h> #include <mediautils/BatteryNotifier.h> #include <mediautils/BatteryNotifier.h> #include <mediautils/ProcessInfo.h> #include <mediautils/ProcessInfo.h> #include <mediautils/SchedulingPolicyService.h> #include <mediautils/SchedulingPolicyService.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/time.h> #include <unistd.h> #include "IMediaResourceMonitor.h" #include "IMediaResourceMonitor.h" #include "ResourceManagerMetrics.h" #include "ResourceManagerMetrics.h" #include "ResourceManagerService.h" #include "ResourceManagerServiceUtils.h" #include "ResourceObserverService.h" #include "ResourceObserverService.h" #include "ServiceLog.h" #include "ServiceLog.h" namespace android { namespace android { class DeathNotifier : public std::enable_shared_from_this<DeathNotifier> { // BinderDiedContext defines the cookie that is passed as DeathRecipient. // Since this can maintain more context than a raw pointer, we can // validate the scope of DeathNotifier, before deferencing it upon the binder death. struct BinderDiedContext { std::weak_ptr<DeathNotifier> mDeathNotifier; }; public: static std::shared_ptr<DeathNotifier> Create( const std::shared_ptr<IResourceManagerClient>& client, const std::shared_ptr<ResourceManagerService>& service, const ClientInfoParcel& clientInfo, bool overrideProcessInfo = false); DeathNotifier(const std::shared_ptr<IResourceManagerClient>& client, const std::shared_ptr<ResourceManagerService>& service, const ClientInfoParcel& clientInfo); virtual ~DeathNotifier() { unlink(); } // Implement death recipient static void BinderDiedCallback(void* cookie); static void BinderUnlinkedCallback(void* cookie); virtual void binderDied(); private: void link() { // Create the context that is passed as cookie to the binder death notification. // The context gets deleted at BinderUnlinkedCallback. mCookie = new BinderDiedContext{.mDeathNotifier = weak_from_this()}; // Register for the callbacks by linking to death notification. AIBinder_linkToDeath(mClient->asBinder().get(), mDeathRecipient.get(), mCookie); } void unlink() { if (mClient != nullptr) { // Unlink from the death notification. AIBinder_unlinkToDeath(mClient->asBinder().get(), mDeathRecipient.get(), mCookie); mClient = nullptr; } } protected: std::shared_ptr<IResourceManagerClient> mClient; std::weak_ptr<ResourceManagerService> mService; const ClientInfoParcel mClientInfo; BinderDiedContext* mCookie; ::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient; }; DeathNotifier::DeathNotifier(const std::shared_ptr<IResourceManagerClient>& client, const std::shared_ptr<ResourceManagerService>& service, const ClientInfoParcel& clientInfo) : mClient(client), mService(service), mClientInfo(clientInfo), mCookie(nullptr), mDeathRecipient(::ndk::ScopedAIBinder_DeathRecipient( AIBinder_DeathRecipient_new(BinderDiedCallback))) { // Setting callback notification when DeathRecipient gets deleted. AIBinder_DeathRecipient_setOnUnlinked(mDeathRecipient.get(), BinderUnlinkedCallback); } //static void DeathNotifier::BinderUnlinkedCallback(void* cookie) { BinderDiedContext* context = reinterpret_cast<BinderDiedContext*>(cookie); // Since we don't need the context anymore, we are deleting it now. delete context; } //static void DeathNotifier::BinderDiedCallback(void* cookie) { BinderDiedContext* context = reinterpret_cast<BinderDiedContext*>(cookie); // Validate the context and check if the DeathNotifier object is still in scope. if (context != nullptr) { std::shared_ptr<DeathNotifier> thiz = context->mDeathNotifier.lock(); if (thiz != nullptr) { thiz->binderDied(); } else { ALOGI("DeathNotifier is out of scope already"); } } } void DeathNotifier::binderDied() { // Don't check for pid validity since we know it's already dead. std::shared_ptr<ResourceManagerService> service = mService.lock(); if (service == nullptr) { ALOGW("ResourceManagerService is dead as well."); return; } service->overridePid(mClientInfo.pid, -1); // thiz is freed in the call below, so it must be last call referring thiz service->removeResource(mClientInfo, false /*checkValid*/); } class OverrideProcessInfoDeathNotifier : public DeathNotifier { public: OverrideProcessInfoDeathNotifier(const std::shared_ptr<IResourceManagerClient>& client, const std::shared_ptr<ResourceManagerService>& service, const ClientInfoParcel& clientInfo) : DeathNotifier(client, service, clientInfo) {} virtual ~OverrideProcessInfoDeathNotifier() {} virtual void binderDied(); }; void OverrideProcessInfoDeathNotifier::binderDied() { // Don't check for pid validity since we know it's already dead. std::shared_ptr<ResourceManagerService> service = mService.lock(); if (service == nullptr) { ALOGW("ResourceManagerService is dead as well."); return; } service->removeProcessInfoOverride(mClientInfo.pid); } std::shared_ptr<DeathNotifier> DeathNotifier::Create( const std::shared_ptr<IResourceManagerClient>& client, const std::shared_ptr<ResourceManagerService>& service, const ClientInfoParcel& clientInfo, bool overrideProcessInfo) { std::shared_ptr<DeathNotifier> deathNotifier = nullptr; if (overrideProcessInfo) { deathNotifier = std::make_shared<OverrideProcessInfoDeathNotifier>( client, service, clientInfo); } else { deathNotifier = std::make_shared<DeathNotifier>(client, service, clientInfo); } if (deathNotifier) { deathNotifier->link(); } return deathNotifier; } static void notifyResourceGranted(int pid, const std::vector<MediaResourceParcel>& resources) { static void notifyResourceGranted(int pid, const std::vector<MediaResourceParcel>& resources) { static const char* const kServiceName = "media_resource_monitor"; static const char* const kServiceName = "media_resource_monitor"; sp<IBinder> binder = defaultServiceManager()->checkService(String16(kServiceName)); sp<IBinder> binder = defaultServiceManager()->checkService(String16(kServiceName)); Loading Loading @@ -334,8 +184,7 @@ ResourceManagerService::ResourceManagerService(const sp<ProcessInfoInterface> &p //static //static void ResourceManagerService::instantiate() { void ResourceManagerService::instantiate() { std::shared_ptr<ResourceManagerService> service = std::shared_ptr<ResourceManagerService> service = Create(); ::ndk::SharedRefBase::make<ResourceManagerService>(); binder_status_t status = binder_status_t status = AServiceManager_addServiceWithFlags( AServiceManager_addServiceWithFlags( service->asBinder().get(), getServiceName(), service->asBinder().get(), getServiceName(), Loading @@ -356,6 +205,16 @@ void ResourceManagerService::instantiate() { //ABinderProcess_startThreadPool(); //ABinderProcess_startThreadPool(); } } std::shared_ptr<ResourceManagerService> ResourceManagerService::Create() { return Create(new ProcessInfo(), new SystemCallbackImpl()); } std::shared_ptr<ResourceManagerService> ResourceManagerService::Create( const sp<ProcessInfoInterface>& processInfo, const sp<SystemCallbackInterface>& systemResource) { return ::ndk::SharedRefBase::make<ResourceManagerService>(processInfo, systemResource); } ResourceManagerService::~ResourceManagerService() {} ResourceManagerService::~ResourceManagerService() {} void ResourceManagerService::setObserverService( void ResourceManagerService::setObserverService( Loading @@ -380,8 +239,7 @@ Status ResourceManagerService::config(const std::vector<MediaResourcePolicyParce return Status::ok(); return Status::ok(); } } void ResourceManagerService::onFirstAdded(const MediaResourceParcel& resource, void ResourceManagerService::onFirstAdded(const MediaResourceParcel& resource, uid_t uid) { const ResourceInfo& clientInfo) { // first time added // first time added if (resource.type == MediaResource::Type::kCpuBoost if (resource.type == MediaResource::Type::kCpuBoost && resource.subType == MediaResource::SubType::kUnspecifiedSubType) { && resource.subType == MediaResource::SubType::kUnspecifiedSubType) { Loading @@ -395,12 +253,11 @@ void ResourceManagerService::onFirstAdded(const MediaResourceParcel& resource, } else if (resource.type == MediaResource::Type::kBattery } else if (resource.type == MediaResource::Type::kBattery && (resource.subType == MediaResource::SubType::kHwVideoCodec && (resource.subType == MediaResource::SubType::kHwVideoCodec || resource.subType == MediaResource::SubType::kSwVideoCodec)) { || resource.subType == MediaResource::SubType::kSwVideoCodec)) { mSystemCB->noteStartVideo(clientInfo.uid); mSystemCB->noteStartVideo(uid); } } } } void ResourceManagerService::onLastRemoved(const MediaResourceParcel& resource, void ResourceManagerService::onLastRemoved(const MediaResourceParcel& resource, uid_t uid) { const ResourceInfo& clientInfo) { if (resource.type == MediaResource::Type::kCpuBoost if (resource.type == MediaResource::Type::kCpuBoost && resource.subType == MediaResource::SubType::kUnspecifiedSubType && resource.subType == MediaResource::SubType::kUnspecifiedSubType && mCpuBoostCount > 0) { && mCpuBoostCount > 0) { Loading @@ -410,24 +267,7 @@ void ResourceManagerService::onLastRemoved(const MediaResourceParcel& resource, } else if (resource.type == MediaResource::Type::kBattery } else if (resource.type == MediaResource::Type::kBattery && (resource.subType == MediaResource::SubType::kHwVideoCodec && (resource.subType == MediaResource::SubType::kHwVideoCodec || resource.subType == MediaResource::SubType::kSwVideoCodec)) { || resource.subType == MediaResource::SubType::kSwVideoCodec)) { mSystemCB->noteStopVideo(clientInfo.uid); mSystemCB->noteStopVideo(uid); } } void ResourceManagerService::mergeResources(MediaResourceParcel& r1, const MediaResourceParcel& r2) { // The resource entry on record is maintained to be in [0,INT64_MAX]. // Clamp if merging in the new resource value causes it to go out of bound. // Note that the new resource value could be negative, eg.DrmSession, the // value goes lower when the session is used more often. During reclaim // the session with the highest value (lowest usage) would be closed. if (r2.value < INT64_MAX - r1.value) { r1.value += r2.value; if (r1.value < 0) { r1.value = 0; } } else { r1.value = INT64_MAX; } } } } Loading Loading @@ -469,7 +309,7 @@ Status ResourceManagerService::addResource(const ClientInfoParcel& clientInfo, ALOGW("Ignoring request to add new resource entry with value <= 0"); ALOGW("Ignoring request to add new resource entry with value <= 0"); continue; continue; } } onFirstAdded(res, info); onFirstAdded(res, info.uid); info.resources[resType] = res; info.resources[resType] = res; } else { } else { mergeResources(info.resources[resType], res); mergeResources(info.resources[resType], res); Loading Loading @@ -540,7 +380,7 @@ Status ResourceManagerService::removeResource(const ClientInfoParcel& clientInfo if (resource.value > res.value) { if (resource.value > res.value) { resource.value -= res.value; resource.value -= res.value; } else { } else { onLastRemoved(res, info); onLastRemoved(res, info.uid); actualRemoved.value = resource.value; actualRemoved.value = resource.value; info.resources.erase(resType); info.resources.erase(resType); } } Loading Loading @@ -595,7 +435,7 @@ Status ResourceManagerService::removeResource(const ClientInfoParcel& clientInfo const ResourceInfo& info = foundClient->second; const ResourceInfo& info = foundClient->second; for (auto it = info.resources.begin(); it != info.resources.end(); it++) { for (auto it = info.resources.begin(); it != info.resources.end(); it++) { onLastRemoved(it->second, info); onLastRemoved(it->second, info.uid); } } // Since this client has been removed, update the metrics collector. // Since this client has been removed, update the metrics collector. Loading @@ -620,15 +460,13 @@ void ResourceManagerService::getClientForResource_l( // Before looking into other processes, check if we have clients marked for // Before looking into other processes, check if we have clients marked for // pending removal in the same process. // pending removal in the same process. uid_t uid = 0; ClientInfo clientInfo; std::shared_ptr<IResourceManagerClient> client; if (getBiggestClientPendingRemoval_l(callingPid, res->type, res->subType, clientInfo)) { if (getBiggestClientPendingRemoval_l(callingPid, res->type, res->subType, uid, &client)) { clientsInfo.emplace_back(clientInfo); clientsInfo.emplace_back(callingPid, uid, client); return; return; } } // Now find client(s) from a lowest priority process that has needed resources. // Now find client(s) from a lowest priority process that has needed resources. ClientInfo clientInfo; if (getLowestPriorityBiggestClient_l(resourceRequestInfo, clientInfo)) { if (getLowestPriorityBiggestClient_l(resourceRequestInfo, clientInfo)) { clientsInfo.push_back(clientInfo); clientsInfo.push_back(clientInfo); } } Loading Loading @@ -769,49 +607,75 @@ void ResourceManagerService::pushReclaimAtom(const ClientInfoParcel& clientInfo, mResourceManagerMetrics->pushReclaimAtom(clientInfo, priorities, targetClients, reclaimed); mResourceManagerMetrics->pushReclaimAtom(clientInfo, priorities, targetClients, reclaimed); } } std::shared_ptr<IResourceManagerClient> ResourceManagerService::getClient( int pid, const int64_t& clientId) const { std::map<int, ResourceInfos>::const_iterator found = mMap.find(pid); if (found == mMap.end()) { ALOGV("%s: didn't find pid %d for clientId %lld", __func__, pid, (long long) clientId); return nullptr; } const ResourceInfos& infos = found->second; ResourceInfos::const_iterator foundClient = infos.find(clientId); if (foundClient == infos.end()) { ALOGV("%s: didn't find clientId %lld", __func__, (long long) clientId); return nullptr; } return foundClient->second.client; } bool ResourceManagerService::removeClient(int pid, const int64_t& clientId) { std::map<int, ResourceInfos>::iterator found = mMap.find(pid); if (found == mMap.end()) { ALOGV("%s: didn't find pid %d for clientId %lld", __func__, pid, (long long) clientId); return false; } ResourceInfos& infos = found->second; ResourceInfos::iterator foundClient = infos.find(clientId); if (foundClient == infos.end()) { ALOGV("%s: didn't find clientId %lld", __func__, (long long) clientId); return false; } infos.erase(foundClient); return true; } bool ResourceManagerService::reclaimUnconditionallyFrom( bool ResourceManagerService::reclaimUnconditionallyFrom( const std::vector<ClientInfo>& targetClients) { const std::vector<ClientInfo>& targetClients) { if (targetClients.size() == 0) { if (targetClients.size() == 0) { return false; return false; } } std::shared_ptr<IResourceManagerClient> failedClient; int64_t failedClientId = -1; int32_t failedClientPid = -1; for (const ClientInfo& targetClient : targetClients) { for (const ClientInfo& targetClient : targetClients) { if (targetClient.mClient == nullptr) { std::shared_ptr<IResourceManagerClient> client = getClient( targetClient.mPid, targetClient.mClientId); if (client == nullptr) { // skip already released clients. // skip already released clients. continue; continue; } } String8 log = String8::format("reclaimResource from client %p", targetClient.mClient.get()); String8 log = String8::format("reclaimResource from client %p", client.get()); mServiceLog->add(log); mServiceLog->add(log); bool success; bool success; Status status = targetClient.mClient->reclaimResource(&success); Status status = client->reclaimResource(&success); if (!status.isOk() || !success) { if (!status.isOk() || !success) { failedClient = targetClient.mClient; failedClientId = targetClient.mClientId; failedClientPid = targetClient.mPid; break; break; } } } } if (failedClient == NULL) { if (failedClientId == -1) { return true; return true; } } int failedClientPid = -1; { { std::scoped_lock lock{mLock}; std::scoped_lock lock{mLock}; bool found = false; bool found = removeClient(failedClientPid, failedClientId); for (auto& [pid, infos] : mMap) { for (const auto& [id, info] : infos) { if (info.client == failedClient) { infos.erase(id); found = true; break; } } if (found) { failedClientPid = pid; break; } } if (found) { if (found) { ALOGW("Failed to reclaim resources from client with pid %d", failedClientPid); ALOGW("Failed to reclaim resources from client with pid %d", failedClientPid); } else { } else { Loading Loading @@ -968,21 +832,19 @@ Status ResourceManagerService::reclaimResourcesFromClientsPendingRemoval(int32_t MediaResource::SubType::kSwVideoCodec, MediaResource::SubType::kSwVideoCodec, MediaResource::SubType::kHwImageCodec, MediaResource::SubType::kHwImageCodec, MediaResource::SubType::kSwImageCodec}) { MediaResource::SubType::kSwImageCodec}) { std::shared_ptr<IResourceManagerClient> client; ClientInfo clientInfo; uid_t uid = 0; if (getBiggestClientPendingRemoval_l(pid, type, subType, clientInfo)) { if (getBiggestClientPendingRemoval_l(pid, type, subType, uid, &client)) { targetClients.emplace_back(clientInfo); targetClients.emplace_back(pid, uid, client); continue; continue; } } } } break; break; // Non-codec resources are shared by audio, video and image codecs (no subtype). // Non-codec resources are shared by audio, video and image codecs (no subtype). default: default: std::shared_ptr<IResourceManagerClient> client; ClientInfo clientInfo; uid_t uid = 0; if (getBiggestClientPendingRemoval_l(pid, type, if (getBiggestClientPendingRemoval_l(pid, type, MediaResource::SubType::kUnspecifiedSubType, uid, &client)) { MediaResource::SubType::kUnspecifiedSubType, clientInfo)) { targetClients.emplace_back(pid, uid, client); targetClients.emplace_back(clientInfo); } } break; break; } } Loading Loading @@ -1024,7 +886,7 @@ bool ResourceManagerService::getAllClients_l( clientsInfo.clear(); clientsInfo.clear(); return false; return false; } } clientsInfo.emplace_back(pid, info.uid, info.client); clientsInfo.emplace_back(pid, info.uid, info.clientId); } } } } } } Loading @@ -1039,15 +901,13 @@ bool ResourceManagerService::getAllClients_l( // - Find the bigegst client (with required resources) from that process. // - Find the bigegst client (with required resources) from that process. bool ResourceManagerService::getLowestPriorityBiggestClient_l( bool ResourceManagerService::getLowestPriorityBiggestClient_l( const ResourceRequestInfo& resourceRequestInfo, const ResourceRequestInfo& resourceRequestInfo, ClientInfo& clientsInfo) { ClientInfo& clientInfo) { int callingPid = resourceRequestInfo.mCallingPid; int callingPid = resourceRequestInfo.mCallingPid; MediaResource::Type type = resourceRequestInfo.mResource->type; MediaResource::Type type = resourceRequestInfo.mResource->type; MediaResource::SubType subType = resourceRequestInfo.mResource->subType; MediaResource::SubType subType = resourceRequestInfo.mResource->subType; int lowestPriorityPid; int lowestPriorityPid; int lowestPriority; int lowestPriority; int callingPriority; int callingPriority; uid_t uid = 0; std::shared_ptr<IResourceManagerClient> client; if (!getPriority_l(callingPid, &callingPriority)) { if (!getPriority_l(callingPid, &callingPriority)) { ALOGE("%s: can't get process priority for pid %d", __func__, callingPid); ALOGE("%s: can't get process priority for pid %d", __func__, callingPid); Loading @@ -1062,13 +922,10 @@ bool ResourceManagerService::getLowestPriorityBiggestClient_l( return false; return false; } } if (!getBiggestClient_l(lowestPriorityPid, type, subType, uid, &client)) { if (!getBiggestClient_l(lowestPriorityPid, type, subType, clientInfo)) { return false; return false; } } clientsInfo.mPid = lowestPriorityPid; clientsInfo.mUid = uid; clientsInfo.mClient = client; ALOGI("%s: CallingProcess(%d:%d) will reclaim from the lowestPriorityProcess(%d:%d)", ALOGI("%s: CallingProcess(%d:%d) will reclaim from the lowestPriorityProcess(%d:%d)", __func__, callingPid, callingPriority, lowestPriorityPid, lowestPriority); __func__, callingPid, callingPriority, lowestPriorityPid, lowestPriority); return true; return true; Loading Loading @@ -1121,15 +978,12 @@ bool ResourceManagerService::isCallingPriorityHigher_l(int callingPid, int pid) } } bool ResourceManagerService::getBiggestClientPendingRemoval_l(int pid, MediaResource::Type type, bool ResourceManagerService::getBiggestClientPendingRemoval_l(int pid, MediaResource::Type type, MediaResource::SubType subType, uid_t& uid, MediaResource::SubType subType, ClientInfo& clientInfo) { std::shared_ptr<IResourceManagerClient> *client) { return getBiggestClient_l(pid, type, subType, clientInfo, true /* pendingRemovalOnly */); return getBiggestClient_l(pid, type, subType, uid, client, true /* pendingRemovalOnly */); } } bool ResourceManagerService::getBiggestClient_l(int pid, MediaResource::Type type, bool ResourceManagerService::getBiggestClient_l(int pid, MediaResource::Type type, MediaResource::SubType subType, uid_t& uid, MediaResource::SubType subType, ClientInfo& clientInfo, bool pendingRemovalOnly) { std::shared_ptr<IResourceManagerClient> *client, bool pendingRemovalOnly) { PidResourceInfosMap::iterator found = mMap.find(pid); PidResourceInfosMap::iterator found = mMap.find(pid); if (found == mMap.end()) { if (found == mMap.end()) { ALOGE_IF(!pendingRemovalOnly, ALOGE_IF(!pendingRemovalOnly, Loading @@ -1137,7 +991,8 @@ bool ResourceManagerService::getBiggestClient_l(int pid, MediaResource::Type typ return false; return false; } } std::shared_ptr<IResourceManagerClient> clientTemp; uid_t uid = -1; int64_t clientId = -1; uint64_t largestValue = 0; uint64_t largestValue = 0; const ResourceInfos& infos = found->second; const ResourceInfos& infos = found->second; for (const auto& [id, info] : infos) { for (const auto& [id, info] : infos) { Loading @@ -1150,21 +1005,23 @@ bool ResourceManagerService::getBiggestClient_l(int pid, MediaResource::Type typ if (hasResourceType(type, subType, resource)) { if (hasResourceType(type, subType, resource)) { if (resource.value > largestValue) { if (resource.value > largestValue) { largestValue = resource.value; largestValue = resource.value; clientTemp = info.client; clientId = info.clientId; uid = info.uid; uid = info.uid; } } } } } } } } if (clientTemp == NULL) { if (clientId == -1) { ALOGE_IF(!pendingRemovalOnly, ALOGE_IF(!pendingRemovalOnly, "getBiggestClient_l: can't find resource type %s and subtype %s for pid %d", "getBiggestClient_l: can't find resource type %s and subtype %s for pid %d", asString(type), asString(subType), pid); asString(type), asString(subType), pid); return false; return false; } } *client = clientTemp; clientInfo.mPid = pid; clientInfo.mUid = uid; clientInfo.mClientId = clientId; return true; return true; } } Loading Loading
media/libmediaplayerservice/tests/DrmSessionManager_test.cpp +2 −2 Original line number Original line Diff line number Diff line Loading @@ -148,8 +148,8 @@ static const std::vector<uint8_t> kTestSessionId3{9, 0}; class DrmSessionManagerTest : public ::testing::Test { class DrmSessionManagerTest : public ::testing::Test { public: public: DrmSessionManagerTest() DrmSessionManagerTest() : mService(::ndk::SharedRefBase::make<ResourceManagerService> : mService(ResourceManagerService::Create( (new FakeProcessInfo(), new FakeSystemCallback())), new FakeProcessInfo(), new FakeSystemCallback())), mDrmSessionManager(new DrmSessionManager(mService)), mDrmSessionManager(new DrmSessionManager(mService)), mTestDrm1(::ndk::SharedRefBase::make<FakeDrm>( mTestDrm1(::ndk::SharedRefBase::make<FakeDrm>( kTestSessionId1, mDrmSessionManager)), kTestSessionId1, mDrmSessionManager)), Loading
services/mediaresourcemanager/ResourceManagerService.cpp +87 −230 Original line number Original line Diff line number Diff line Loading @@ -24,169 +24,19 @@ #include <binder/IPCThreadState.h> #include <binder/IPCThreadState.h> #include <binder/IServiceManager.h> #include <binder/IServiceManager.h> #include <cutils/sched_policy.h> #include <cutils/sched_policy.h> #include <dirent.h> #include <media/MediaResourcePolicy.h> #include <media/MediaResourcePolicy.h> #include <media/stagefright/foundation/ABase.h> #include <media/stagefright/foundation/ABase.h> #include <mediautils/BatteryNotifier.h> #include <mediautils/BatteryNotifier.h> #include <mediautils/ProcessInfo.h> #include <mediautils/ProcessInfo.h> #include <mediautils/SchedulingPolicyService.h> #include <mediautils/SchedulingPolicyService.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/time.h> #include <unistd.h> #include "IMediaResourceMonitor.h" #include "IMediaResourceMonitor.h" #include "ResourceManagerMetrics.h" #include "ResourceManagerMetrics.h" #include "ResourceManagerService.h" #include "ResourceManagerServiceUtils.h" #include "ResourceObserverService.h" #include "ResourceObserverService.h" #include "ServiceLog.h" #include "ServiceLog.h" namespace android { namespace android { class DeathNotifier : public std::enable_shared_from_this<DeathNotifier> { // BinderDiedContext defines the cookie that is passed as DeathRecipient. // Since this can maintain more context than a raw pointer, we can // validate the scope of DeathNotifier, before deferencing it upon the binder death. struct BinderDiedContext { std::weak_ptr<DeathNotifier> mDeathNotifier; }; public: static std::shared_ptr<DeathNotifier> Create( const std::shared_ptr<IResourceManagerClient>& client, const std::shared_ptr<ResourceManagerService>& service, const ClientInfoParcel& clientInfo, bool overrideProcessInfo = false); DeathNotifier(const std::shared_ptr<IResourceManagerClient>& client, const std::shared_ptr<ResourceManagerService>& service, const ClientInfoParcel& clientInfo); virtual ~DeathNotifier() { unlink(); } // Implement death recipient static void BinderDiedCallback(void* cookie); static void BinderUnlinkedCallback(void* cookie); virtual void binderDied(); private: void link() { // Create the context that is passed as cookie to the binder death notification. // The context gets deleted at BinderUnlinkedCallback. mCookie = new BinderDiedContext{.mDeathNotifier = weak_from_this()}; // Register for the callbacks by linking to death notification. AIBinder_linkToDeath(mClient->asBinder().get(), mDeathRecipient.get(), mCookie); } void unlink() { if (mClient != nullptr) { // Unlink from the death notification. AIBinder_unlinkToDeath(mClient->asBinder().get(), mDeathRecipient.get(), mCookie); mClient = nullptr; } } protected: std::shared_ptr<IResourceManagerClient> mClient; std::weak_ptr<ResourceManagerService> mService; const ClientInfoParcel mClientInfo; BinderDiedContext* mCookie; ::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient; }; DeathNotifier::DeathNotifier(const std::shared_ptr<IResourceManagerClient>& client, const std::shared_ptr<ResourceManagerService>& service, const ClientInfoParcel& clientInfo) : mClient(client), mService(service), mClientInfo(clientInfo), mCookie(nullptr), mDeathRecipient(::ndk::ScopedAIBinder_DeathRecipient( AIBinder_DeathRecipient_new(BinderDiedCallback))) { // Setting callback notification when DeathRecipient gets deleted. AIBinder_DeathRecipient_setOnUnlinked(mDeathRecipient.get(), BinderUnlinkedCallback); } //static void DeathNotifier::BinderUnlinkedCallback(void* cookie) { BinderDiedContext* context = reinterpret_cast<BinderDiedContext*>(cookie); // Since we don't need the context anymore, we are deleting it now. delete context; } //static void DeathNotifier::BinderDiedCallback(void* cookie) { BinderDiedContext* context = reinterpret_cast<BinderDiedContext*>(cookie); // Validate the context and check if the DeathNotifier object is still in scope. if (context != nullptr) { std::shared_ptr<DeathNotifier> thiz = context->mDeathNotifier.lock(); if (thiz != nullptr) { thiz->binderDied(); } else { ALOGI("DeathNotifier is out of scope already"); } } } void DeathNotifier::binderDied() { // Don't check for pid validity since we know it's already dead. std::shared_ptr<ResourceManagerService> service = mService.lock(); if (service == nullptr) { ALOGW("ResourceManagerService is dead as well."); return; } service->overridePid(mClientInfo.pid, -1); // thiz is freed in the call below, so it must be last call referring thiz service->removeResource(mClientInfo, false /*checkValid*/); } class OverrideProcessInfoDeathNotifier : public DeathNotifier { public: OverrideProcessInfoDeathNotifier(const std::shared_ptr<IResourceManagerClient>& client, const std::shared_ptr<ResourceManagerService>& service, const ClientInfoParcel& clientInfo) : DeathNotifier(client, service, clientInfo) {} virtual ~OverrideProcessInfoDeathNotifier() {} virtual void binderDied(); }; void OverrideProcessInfoDeathNotifier::binderDied() { // Don't check for pid validity since we know it's already dead. std::shared_ptr<ResourceManagerService> service = mService.lock(); if (service == nullptr) { ALOGW("ResourceManagerService is dead as well."); return; } service->removeProcessInfoOverride(mClientInfo.pid); } std::shared_ptr<DeathNotifier> DeathNotifier::Create( const std::shared_ptr<IResourceManagerClient>& client, const std::shared_ptr<ResourceManagerService>& service, const ClientInfoParcel& clientInfo, bool overrideProcessInfo) { std::shared_ptr<DeathNotifier> deathNotifier = nullptr; if (overrideProcessInfo) { deathNotifier = std::make_shared<OverrideProcessInfoDeathNotifier>( client, service, clientInfo); } else { deathNotifier = std::make_shared<DeathNotifier>(client, service, clientInfo); } if (deathNotifier) { deathNotifier->link(); } return deathNotifier; } static void notifyResourceGranted(int pid, const std::vector<MediaResourceParcel>& resources) { static void notifyResourceGranted(int pid, const std::vector<MediaResourceParcel>& resources) { static const char* const kServiceName = "media_resource_monitor"; static const char* const kServiceName = "media_resource_monitor"; sp<IBinder> binder = defaultServiceManager()->checkService(String16(kServiceName)); sp<IBinder> binder = defaultServiceManager()->checkService(String16(kServiceName)); Loading Loading @@ -334,8 +184,7 @@ ResourceManagerService::ResourceManagerService(const sp<ProcessInfoInterface> &p //static //static void ResourceManagerService::instantiate() { void ResourceManagerService::instantiate() { std::shared_ptr<ResourceManagerService> service = std::shared_ptr<ResourceManagerService> service = Create(); ::ndk::SharedRefBase::make<ResourceManagerService>(); binder_status_t status = binder_status_t status = AServiceManager_addServiceWithFlags( AServiceManager_addServiceWithFlags( service->asBinder().get(), getServiceName(), service->asBinder().get(), getServiceName(), Loading @@ -356,6 +205,16 @@ void ResourceManagerService::instantiate() { //ABinderProcess_startThreadPool(); //ABinderProcess_startThreadPool(); } } std::shared_ptr<ResourceManagerService> ResourceManagerService::Create() { return Create(new ProcessInfo(), new SystemCallbackImpl()); } std::shared_ptr<ResourceManagerService> ResourceManagerService::Create( const sp<ProcessInfoInterface>& processInfo, const sp<SystemCallbackInterface>& systemResource) { return ::ndk::SharedRefBase::make<ResourceManagerService>(processInfo, systemResource); } ResourceManagerService::~ResourceManagerService() {} ResourceManagerService::~ResourceManagerService() {} void ResourceManagerService::setObserverService( void ResourceManagerService::setObserverService( Loading @@ -380,8 +239,7 @@ Status ResourceManagerService::config(const std::vector<MediaResourcePolicyParce return Status::ok(); return Status::ok(); } } void ResourceManagerService::onFirstAdded(const MediaResourceParcel& resource, void ResourceManagerService::onFirstAdded(const MediaResourceParcel& resource, uid_t uid) { const ResourceInfo& clientInfo) { // first time added // first time added if (resource.type == MediaResource::Type::kCpuBoost if (resource.type == MediaResource::Type::kCpuBoost && resource.subType == MediaResource::SubType::kUnspecifiedSubType) { && resource.subType == MediaResource::SubType::kUnspecifiedSubType) { Loading @@ -395,12 +253,11 @@ void ResourceManagerService::onFirstAdded(const MediaResourceParcel& resource, } else if (resource.type == MediaResource::Type::kBattery } else if (resource.type == MediaResource::Type::kBattery && (resource.subType == MediaResource::SubType::kHwVideoCodec && (resource.subType == MediaResource::SubType::kHwVideoCodec || resource.subType == MediaResource::SubType::kSwVideoCodec)) { || resource.subType == MediaResource::SubType::kSwVideoCodec)) { mSystemCB->noteStartVideo(clientInfo.uid); mSystemCB->noteStartVideo(uid); } } } } void ResourceManagerService::onLastRemoved(const MediaResourceParcel& resource, void ResourceManagerService::onLastRemoved(const MediaResourceParcel& resource, uid_t uid) { const ResourceInfo& clientInfo) { if (resource.type == MediaResource::Type::kCpuBoost if (resource.type == MediaResource::Type::kCpuBoost && resource.subType == MediaResource::SubType::kUnspecifiedSubType && resource.subType == MediaResource::SubType::kUnspecifiedSubType && mCpuBoostCount > 0) { && mCpuBoostCount > 0) { Loading @@ -410,24 +267,7 @@ void ResourceManagerService::onLastRemoved(const MediaResourceParcel& resource, } else if (resource.type == MediaResource::Type::kBattery } else if (resource.type == MediaResource::Type::kBattery && (resource.subType == MediaResource::SubType::kHwVideoCodec && (resource.subType == MediaResource::SubType::kHwVideoCodec || resource.subType == MediaResource::SubType::kSwVideoCodec)) { || resource.subType == MediaResource::SubType::kSwVideoCodec)) { mSystemCB->noteStopVideo(clientInfo.uid); mSystemCB->noteStopVideo(uid); } } void ResourceManagerService::mergeResources(MediaResourceParcel& r1, const MediaResourceParcel& r2) { // The resource entry on record is maintained to be in [0,INT64_MAX]. // Clamp if merging in the new resource value causes it to go out of bound. // Note that the new resource value could be negative, eg.DrmSession, the // value goes lower when the session is used more often. During reclaim // the session with the highest value (lowest usage) would be closed. if (r2.value < INT64_MAX - r1.value) { r1.value += r2.value; if (r1.value < 0) { r1.value = 0; } } else { r1.value = INT64_MAX; } } } } Loading Loading @@ -469,7 +309,7 @@ Status ResourceManagerService::addResource(const ClientInfoParcel& clientInfo, ALOGW("Ignoring request to add new resource entry with value <= 0"); ALOGW("Ignoring request to add new resource entry with value <= 0"); continue; continue; } } onFirstAdded(res, info); onFirstAdded(res, info.uid); info.resources[resType] = res; info.resources[resType] = res; } else { } else { mergeResources(info.resources[resType], res); mergeResources(info.resources[resType], res); Loading Loading @@ -540,7 +380,7 @@ Status ResourceManagerService::removeResource(const ClientInfoParcel& clientInfo if (resource.value > res.value) { if (resource.value > res.value) { resource.value -= res.value; resource.value -= res.value; } else { } else { onLastRemoved(res, info); onLastRemoved(res, info.uid); actualRemoved.value = resource.value; actualRemoved.value = resource.value; info.resources.erase(resType); info.resources.erase(resType); } } Loading Loading @@ -595,7 +435,7 @@ Status ResourceManagerService::removeResource(const ClientInfoParcel& clientInfo const ResourceInfo& info = foundClient->second; const ResourceInfo& info = foundClient->second; for (auto it = info.resources.begin(); it != info.resources.end(); it++) { for (auto it = info.resources.begin(); it != info.resources.end(); it++) { onLastRemoved(it->second, info); onLastRemoved(it->second, info.uid); } } // Since this client has been removed, update the metrics collector. // Since this client has been removed, update the metrics collector. Loading @@ -620,15 +460,13 @@ void ResourceManagerService::getClientForResource_l( // Before looking into other processes, check if we have clients marked for // Before looking into other processes, check if we have clients marked for // pending removal in the same process. // pending removal in the same process. uid_t uid = 0; ClientInfo clientInfo; std::shared_ptr<IResourceManagerClient> client; if (getBiggestClientPendingRemoval_l(callingPid, res->type, res->subType, clientInfo)) { if (getBiggestClientPendingRemoval_l(callingPid, res->type, res->subType, uid, &client)) { clientsInfo.emplace_back(clientInfo); clientsInfo.emplace_back(callingPid, uid, client); return; return; } } // Now find client(s) from a lowest priority process that has needed resources. // Now find client(s) from a lowest priority process that has needed resources. ClientInfo clientInfo; if (getLowestPriorityBiggestClient_l(resourceRequestInfo, clientInfo)) { if (getLowestPriorityBiggestClient_l(resourceRequestInfo, clientInfo)) { clientsInfo.push_back(clientInfo); clientsInfo.push_back(clientInfo); } } Loading Loading @@ -769,49 +607,75 @@ void ResourceManagerService::pushReclaimAtom(const ClientInfoParcel& clientInfo, mResourceManagerMetrics->pushReclaimAtom(clientInfo, priorities, targetClients, reclaimed); mResourceManagerMetrics->pushReclaimAtom(clientInfo, priorities, targetClients, reclaimed); } } std::shared_ptr<IResourceManagerClient> ResourceManagerService::getClient( int pid, const int64_t& clientId) const { std::map<int, ResourceInfos>::const_iterator found = mMap.find(pid); if (found == mMap.end()) { ALOGV("%s: didn't find pid %d for clientId %lld", __func__, pid, (long long) clientId); return nullptr; } const ResourceInfos& infos = found->second; ResourceInfos::const_iterator foundClient = infos.find(clientId); if (foundClient == infos.end()) { ALOGV("%s: didn't find clientId %lld", __func__, (long long) clientId); return nullptr; } return foundClient->second.client; } bool ResourceManagerService::removeClient(int pid, const int64_t& clientId) { std::map<int, ResourceInfos>::iterator found = mMap.find(pid); if (found == mMap.end()) { ALOGV("%s: didn't find pid %d for clientId %lld", __func__, pid, (long long) clientId); return false; } ResourceInfos& infos = found->second; ResourceInfos::iterator foundClient = infos.find(clientId); if (foundClient == infos.end()) { ALOGV("%s: didn't find clientId %lld", __func__, (long long) clientId); return false; } infos.erase(foundClient); return true; } bool ResourceManagerService::reclaimUnconditionallyFrom( bool ResourceManagerService::reclaimUnconditionallyFrom( const std::vector<ClientInfo>& targetClients) { const std::vector<ClientInfo>& targetClients) { if (targetClients.size() == 0) { if (targetClients.size() == 0) { return false; return false; } } std::shared_ptr<IResourceManagerClient> failedClient; int64_t failedClientId = -1; int32_t failedClientPid = -1; for (const ClientInfo& targetClient : targetClients) { for (const ClientInfo& targetClient : targetClients) { if (targetClient.mClient == nullptr) { std::shared_ptr<IResourceManagerClient> client = getClient( targetClient.mPid, targetClient.mClientId); if (client == nullptr) { // skip already released clients. // skip already released clients. continue; continue; } } String8 log = String8::format("reclaimResource from client %p", targetClient.mClient.get()); String8 log = String8::format("reclaimResource from client %p", client.get()); mServiceLog->add(log); mServiceLog->add(log); bool success; bool success; Status status = targetClient.mClient->reclaimResource(&success); Status status = client->reclaimResource(&success); if (!status.isOk() || !success) { if (!status.isOk() || !success) { failedClient = targetClient.mClient; failedClientId = targetClient.mClientId; failedClientPid = targetClient.mPid; break; break; } } } } if (failedClient == NULL) { if (failedClientId == -1) { return true; return true; } } int failedClientPid = -1; { { std::scoped_lock lock{mLock}; std::scoped_lock lock{mLock}; bool found = false; bool found = removeClient(failedClientPid, failedClientId); for (auto& [pid, infos] : mMap) { for (const auto& [id, info] : infos) { if (info.client == failedClient) { infos.erase(id); found = true; break; } } if (found) { failedClientPid = pid; break; } } if (found) { if (found) { ALOGW("Failed to reclaim resources from client with pid %d", failedClientPid); ALOGW("Failed to reclaim resources from client with pid %d", failedClientPid); } else { } else { Loading Loading @@ -968,21 +832,19 @@ Status ResourceManagerService::reclaimResourcesFromClientsPendingRemoval(int32_t MediaResource::SubType::kSwVideoCodec, MediaResource::SubType::kSwVideoCodec, MediaResource::SubType::kHwImageCodec, MediaResource::SubType::kHwImageCodec, MediaResource::SubType::kSwImageCodec}) { MediaResource::SubType::kSwImageCodec}) { std::shared_ptr<IResourceManagerClient> client; ClientInfo clientInfo; uid_t uid = 0; if (getBiggestClientPendingRemoval_l(pid, type, subType, clientInfo)) { if (getBiggestClientPendingRemoval_l(pid, type, subType, uid, &client)) { targetClients.emplace_back(clientInfo); targetClients.emplace_back(pid, uid, client); continue; continue; } } } } break; break; // Non-codec resources are shared by audio, video and image codecs (no subtype). // Non-codec resources are shared by audio, video and image codecs (no subtype). default: default: std::shared_ptr<IResourceManagerClient> client; ClientInfo clientInfo; uid_t uid = 0; if (getBiggestClientPendingRemoval_l(pid, type, if (getBiggestClientPendingRemoval_l(pid, type, MediaResource::SubType::kUnspecifiedSubType, uid, &client)) { MediaResource::SubType::kUnspecifiedSubType, clientInfo)) { targetClients.emplace_back(pid, uid, client); targetClients.emplace_back(clientInfo); } } break; break; } } Loading Loading @@ -1024,7 +886,7 @@ bool ResourceManagerService::getAllClients_l( clientsInfo.clear(); clientsInfo.clear(); return false; return false; } } clientsInfo.emplace_back(pid, info.uid, info.client); clientsInfo.emplace_back(pid, info.uid, info.clientId); } } } } } } Loading @@ -1039,15 +901,13 @@ bool ResourceManagerService::getAllClients_l( // - Find the bigegst client (with required resources) from that process. // - Find the bigegst client (with required resources) from that process. bool ResourceManagerService::getLowestPriorityBiggestClient_l( bool ResourceManagerService::getLowestPriorityBiggestClient_l( const ResourceRequestInfo& resourceRequestInfo, const ResourceRequestInfo& resourceRequestInfo, ClientInfo& clientsInfo) { ClientInfo& clientInfo) { int callingPid = resourceRequestInfo.mCallingPid; int callingPid = resourceRequestInfo.mCallingPid; MediaResource::Type type = resourceRequestInfo.mResource->type; MediaResource::Type type = resourceRequestInfo.mResource->type; MediaResource::SubType subType = resourceRequestInfo.mResource->subType; MediaResource::SubType subType = resourceRequestInfo.mResource->subType; int lowestPriorityPid; int lowestPriorityPid; int lowestPriority; int lowestPriority; int callingPriority; int callingPriority; uid_t uid = 0; std::shared_ptr<IResourceManagerClient> client; if (!getPriority_l(callingPid, &callingPriority)) { if (!getPriority_l(callingPid, &callingPriority)) { ALOGE("%s: can't get process priority for pid %d", __func__, callingPid); ALOGE("%s: can't get process priority for pid %d", __func__, callingPid); Loading @@ -1062,13 +922,10 @@ bool ResourceManagerService::getLowestPriorityBiggestClient_l( return false; return false; } } if (!getBiggestClient_l(lowestPriorityPid, type, subType, uid, &client)) { if (!getBiggestClient_l(lowestPriorityPid, type, subType, clientInfo)) { return false; return false; } } clientsInfo.mPid = lowestPriorityPid; clientsInfo.mUid = uid; clientsInfo.mClient = client; ALOGI("%s: CallingProcess(%d:%d) will reclaim from the lowestPriorityProcess(%d:%d)", ALOGI("%s: CallingProcess(%d:%d) will reclaim from the lowestPriorityProcess(%d:%d)", __func__, callingPid, callingPriority, lowestPriorityPid, lowestPriority); __func__, callingPid, callingPriority, lowestPriorityPid, lowestPriority); return true; return true; Loading Loading @@ -1121,15 +978,12 @@ bool ResourceManagerService::isCallingPriorityHigher_l(int callingPid, int pid) } } bool ResourceManagerService::getBiggestClientPendingRemoval_l(int pid, MediaResource::Type type, bool ResourceManagerService::getBiggestClientPendingRemoval_l(int pid, MediaResource::Type type, MediaResource::SubType subType, uid_t& uid, MediaResource::SubType subType, ClientInfo& clientInfo) { std::shared_ptr<IResourceManagerClient> *client) { return getBiggestClient_l(pid, type, subType, clientInfo, true /* pendingRemovalOnly */); return getBiggestClient_l(pid, type, subType, uid, client, true /* pendingRemovalOnly */); } } bool ResourceManagerService::getBiggestClient_l(int pid, MediaResource::Type type, bool ResourceManagerService::getBiggestClient_l(int pid, MediaResource::Type type, MediaResource::SubType subType, uid_t& uid, MediaResource::SubType subType, ClientInfo& clientInfo, bool pendingRemovalOnly) { std::shared_ptr<IResourceManagerClient> *client, bool pendingRemovalOnly) { PidResourceInfosMap::iterator found = mMap.find(pid); PidResourceInfosMap::iterator found = mMap.find(pid); if (found == mMap.end()) { if (found == mMap.end()) { ALOGE_IF(!pendingRemovalOnly, ALOGE_IF(!pendingRemovalOnly, Loading @@ -1137,7 +991,8 @@ bool ResourceManagerService::getBiggestClient_l(int pid, MediaResource::Type typ return false; return false; } } std::shared_ptr<IResourceManagerClient> clientTemp; uid_t uid = -1; int64_t clientId = -1; uint64_t largestValue = 0; uint64_t largestValue = 0; const ResourceInfos& infos = found->second; const ResourceInfos& infos = found->second; for (const auto& [id, info] : infos) { for (const auto& [id, info] : infos) { Loading @@ -1150,21 +1005,23 @@ bool ResourceManagerService::getBiggestClient_l(int pid, MediaResource::Type typ if (hasResourceType(type, subType, resource)) { if (hasResourceType(type, subType, resource)) { if (resource.value > largestValue) { if (resource.value > largestValue) { largestValue = resource.value; largestValue = resource.value; clientTemp = info.client; clientId = info.clientId; uid = info.uid; uid = info.uid; } } } } } } } } if (clientTemp == NULL) { if (clientId == -1) { ALOGE_IF(!pendingRemovalOnly, ALOGE_IF(!pendingRemovalOnly, "getBiggestClient_l: can't find resource type %s and subtype %s for pid %d", "getBiggestClient_l: can't find resource type %s and subtype %s for pid %d", asString(type), asString(subType), pid); asString(type), asString(subType), pid); return false; return false; } } *client = clientTemp; clientInfo.mPid = pid; clientInfo.mUid = uid; clientInfo.mClientId = clientId; return true; return true; } } Loading