resourcemanager: move common code into different source.
This change moves all the common code into a separate source
to enable extenstion of resource manager service implementation.
And also, a new creation function is added to enable the same.
Bug: 294886363
Test: atest android.media.misc.cts.ResourceManagerTest
atest android.media.misc.cts.ResourceManagerMultiTest
/data/nativetest64/ResourceManagerService_test/ResourceManagerService_test
/data/nativetest64/ResourceObserverService_test/ResourceObserverService_test
Merged-In: I70f4776979104f1468e2791bb8e977ab85d9676a
Change-Id: I70f4776979104f1468e2791bb8e977ab85d9676a
diff --git a/services/mediaresourcemanager/ResourceManagerServiceUtils.cpp b/services/mediaresourcemanager/ResourceManagerServiceUtils.cpp
index 892b1b3..de682f8 100644
--- a/services/mediaresourcemanager/ResourceManagerServiceUtils.cpp
+++ b/services/mediaresourcemanager/ResourceManagerServiceUtils.cpp
@@ -24,29 +24,32 @@
namespace android {
+// Bunch of utility functions that looks for a specific Resource.
+// Check whether a given resource (of type and subtype) is found in given resource parcel.
bool hasResourceType(MediaResource::Type type, MediaResource::SubType subType,
- const MediaResourceParcel& resource) {
+ const MediaResourceParcel& resource) {
if (type != resource.type) {
return false;
}
switch (type) {
- // Codec subtypes (e.g. video vs. audio) are each considered separate resources, so
- // compare the subtypes as well.
- case MediaResource::Type::kSecureCodec:
- case MediaResource::Type::kNonSecureCodec:
- if (resource.subType == subType) {
- return true;
- }
- break;
- // Non-codec resources are not segregated by the subtype (e.g. video vs. audio).
- default:
+ // Codec subtypes (e.g. video vs. audio and hw vs. sw) are each considered separate resources,
+ // so compare the subtypes as well.
+ case MediaResource::Type::kSecureCodec:
+ case MediaResource::Type::kNonSecureCodec:
+ if (resource.subType == subType) {
return true;
+ }
+ break;
+ // Non-codec resources are not segregated by the subtype (e.g. video vs. audio).
+ default:
+ return true;
}
return false;
}
+// Check whether a given resource (of type and subtype) is found in given resource list.
bool hasResourceType(MediaResource::Type type, MediaResource::SubType subType,
- const ResourceList& resources) {
+ const ResourceList& resources) {
for (auto it = resources.begin(); it != resources.end(); it++) {
if (hasResourceType(type, subType, it->second)) {
return true;
@@ -55,8 +58,9 @@
return false;
}
+// Check whether a given resource (of type and subtype) is found in given resource info list.
bool hasResourceType(MediaResource::Type type, MediaResource::SubType subType,
- const ResourceInfos& infos) {
+ const ResourceInfos& infos) {
for (const auto& [id, info] : infos) {
if (hasResourceType(type, subType, info.resources)) {
return true;
@@ -77,12 +81,17 @@
return found->second;
}
+// Return modifiable ResourceInfo for a given client (look up by client id)
+// from the map of ResourceInfos.
+// If the item is not in the map, create one and add it to the map.
ResourceInfo& getResourceInfoForEdit(const ClientInfoParcel& clientInfo,
- const std::shared_ptr<IResourceManagerClient>& client, ResourceInfos& infos) {
+ const std::shared_ptr<IResourceManagerClient>& client,
+ ResourceInfos& infos) {
ResourceInfos::iterator found = infos.find(clientInfo.id);
if (found == infos.end()) {
- ResourceInfo info{.uid = static_cast<uid_t>(clientInfo.uid),
+ ResourceInfo info{.pid = clientInfo.pid,
+ .uid = static_cast<uid_t>(clientInfo.uid),
.clientId = clientInfo.id,
.name = clientInfo.name.empty()? "<unknown client>" : clientInfo.name,
.client = client,
@@ -95,4 +104,102 @@
return found->second;
}
+// Merge resources from r2 into r1.
+void 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;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////
+////////////// Death Notifier implementation ////////////////////////
+///////////////////////////////////////////////////////////////////////
+
+DeathNotifier::DeathNotifier(const std::shared_ptr<IResourceManagerClient>& client,
+ const std::weak_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*/);
+}
+
+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::weak_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;
+}
+
} // namespace android