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/ResourceManagerService.cpp b/services/mediaresourcemanager/ResourceManagerService.cpp
index c5eb537..1953237 100644
--- a/services/mediaresourcemanager/ResourceManagerService.cpp
+++ b/services/mediaresourcemanager/ResourceManagerService.cpp
@@ -24,143 +24,19 @@
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <cutils/sched_policy.h>
-#include <dirent.h>
#include <media/MediaResourcePolicy.h>
#include <media/stagefright/foundation/ABase.h>
#include <mediautils/BatteryNotifier.h>
#include <mediautils/ProcessInfo.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 "ResourceManagerMetrics.h"
-#include "ResourceManagerService.h"
-#include "ResourceManagerServiceUtils.h"
#include "ResourceObserverService.h"
#include "ServiceLog.h"
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:
- DeathNotifier(const std::shared_ptr<IResourceManagerClient>& client,
- const std::shared_ptr<ResourceManagerService>& service,
- const ClientInfoParcel& clientInfo,
- AIBinder_DeathRecipient* recipient);
-
- virtual ~DeathNotifier() {
- unlink();
- }
-
- void unlink() {
- if (mClient != nullptr) {
- // Register for the callbacks by linking to death notification.
- AIBinder_unlinkToDeath(mClient->asBinder().get(), mRecipient, mCookie);
- mClient = nullptr;
- }
- }
-
- // 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(), mRecipient, mCookie);
- }
-
-protected:
- std::shared_ptr<IResourceManagerClient> mClient;
- std::weak_ptr<ResourceManagerService> mService;
- const ClientInfoParcel mClientInfo;
- AIBinder_DeathRecipient* mRecipient;
- BinderDiedContext* mCookie;
-};
-
-DeathNotifier::DeathNotifier(const std::shared_ptr<IResourceManagerClient>& client,
- const std::shared_ptr<ResourceManagerService>& service,
- const ClientInfoParcel& clientInfo,
- AIBinder_DeathRecipient* recipient)
- : mClient(client), mService(service), mClientInfo(clientInfo),
- mRecipient(recipient), mCookie(nullptr) {
- link();
-}
-
-//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,
- AIBinder_DeathRecipient* recipient)
- : DeathNotifier(client, service, clientInfo, recipient) {}
-
- 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);
-}
-
static void notifyResourceGranted(int pid, const std::vector<MediaResourceParcel>& resources) {
static const char* const kServiceName = "media_resource_monitor";
sp<IBinder> binder = defaultServiceManager()->checkService(String16(kServiceName));
@@ -300,9 +176,7 @@
mServiceLog(new ServiceLog()),
mSupportsMultipleSecureCodecs(true),
mSupportsSecureWithNonSecureCodec(true),
- mCpuBoostCount(0),
- mDeathRecipient(::ndk::ScopedAIBinder_DeathRecipient(
- AIBinder_DeathRecipient_new(DeathNotifier::BinderDiedCallback))) {
+ mCpuBoostCount(0) {
mSystemCB->noteResetVideo();
// Create ResourceManagerMetrics that handles all the metrics.
mResourceManagerMetrics = std::make_unique<ResourceManagerMetrics>(mProcessInfo);
@@ -310,8 +184,7 @@
//static
void ResourceManagerService::instantiate() {
- std::shared_ptr<ResourceManagerService> service =
- ::ndk::SharedRefBase::make<ResourceManagerService>();
+ std::shared_ptr<ResourceManagerService> service = Create();
binder_status_t status =
AServiceManager_addServiceWithFlags(
service->asBinder().get(), getServiceName(),
@@ -332,6 +205,16 @@
//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() {}
void ResourceManagerService::setObserverService(
@@ -356,8 +239,7 @@
return Status::ok();
}
-void ResourceManagerService::onFirstAdded(const MediaResourceParcel& resource,
- const ResourceInfo& clientInfo) {
+void ResourceManagerService::onFirstAdded(const MediaResourceParcel& resource, uid_t uid) {
// first time added
if (resource.type == MediaResource::Type::kCpuBoost
&& resource.subType == MediaResource::SubType::kUnspecifiedSubType) {
@@ -371,12 +253,11 @@
} else if (resource.type == MediaResource::Type::kBattery
&& (resource.subType == MediaResource::SubType::kHwVideoCodec
|| resource.subType == MediaResource::SubType::kSwVideoCodec)) {
- mSystemCB->noteStartVideo(clientInfo.uid);
+ mSystemCB->noteStartVideo(uid);
}
}
-void ResourceManagerService::onLastRemoved(const MediaResourceParcel& resource,
- const ResourceInfo& clientInfo) {
+void ResourceManagerService::onLastRemoved(const MediaResourceParcel& resource, uid_t uid) {
if (resource.type == MediaResource::Type::kCpuBoost
&& resource.subType == MediaResource::SubType::kUnspecifiedSubType
&& mCpuBoostCount > 0) {
@@ -386,24 +267,7 @@
} else if (resource.type == MediaResource::Type::kBattery
&& (resource.subType == MediaResource::SubType::kHwVideoCodec
|| resource.subType == MediaResource::SubType::kSwVideoCodec)) {
- mSystemCB->noteStopVideo(clientInfo.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;
+ mSystemCB->noteStopVideo(uid);
}
}
@@ -445,7 +309,7 @@
ALOGW("Ignoring request to add new resource entry with value <= 0");
continue;
}
- onFirstAdded(res, info);
+ onFirstAdded(res, info.uid);
info.resources[resType] = res;
} else {
mergeResources(info.resources[resType], res);
@@ -459,8 +323,8 @@
}
}
if (info.deathNotifier == nullptr && client != nullptr) {
- info.deathNotifier = std::make_shared<DeathNotifier>(
- client, ref<ResourceManagerService>(), clientInfo, mDeathRecipient.get());
+ info.deathNotifier = DeathNotifier::Create(
+ client, ref<ResourceManagerService>(), clientInfo);
}
if (mObserverService != nullptr && !resourceAdded.empty()) {
mObserverService->onResourceAdded(uid, pid, resourceAdded);
@@ -516,7 +380,7 @@
if (resource.value > res.value) {
resource.value -= res.value;
} else {
- onLastRemoved(res, info);
+ onLastRemoved(res, info.uid);
actualRemoved.value = resource.value;
info.resources.erase(resType);
}
@@ -571,7 +435,7 @@
const ResourceInfo& info = foundClient->second;
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.
@@ -596,15 +460,13 @@
// Before looking into other processes, check if we have clients marked for
// pending removal in the same process.
- uid_t uid = 0;
- std::shared_ptr<IResourceManagerClient> client;
- if (getBiggestClientPendingRemoval_l(callingPid, res->type, res->subType, uid, &client)) {
- clientsInfo.emplace_back(callingPid, uid, client);
+ ClientInfo clientInfo;
+ if (getBiggestClientPendingRemoval_l(callingPid, res->type, res->subType, clientInfo)) {
+ clientsInfo.emplace_back(clientInfo);
return;
}
// Now find client(s) from a lowest priority process that has needed resources.
- ClientInfo clientInfo;
if (getLowestPriorityBiggestClient_l(resourceRequestInfo, clientInfo)) {
clientsInfo.push_back(clientInfo);
}
@@ -745,49 +607,75 @@
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(
const std::vector<ClientInfo>& targetClients) {
if (targetClients.size() == 0) {
return false;
}
- std::shared_ptr<IResourceManagerClient> failedClient;
+ int64_t failedClientId = -1;
+ int32_t failedClientPid = -1;
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.
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);
bool success;
- Status status = targetClient.mClient->reclaimResource(&success);
+ Status status = client->reclaimResource(&success);
if (!status.isOk() || !success) {
- failedClient = targetClient.mClient;
+ failedClientId = targetClient.mClientId;
+ failedClientPid = targetClient.mPid;
break;
}
}
- if (failedClient == NULL) {
+ if (failedClientId == -1) {
return true;
}
- int failedClientPid = -1;
{
std::scoped_lock lock{mLock};
- bool found = false;
- 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;
- }
- }
+ bool found = removeClient(failedClientPid, failedClientId);
if (found) {
ALOGW("Failed to reclaim resources from client with pid %d", failedClientPid);
} else {
@@ -858,8 +746,8 @@
.uid = 0,
.id = 0,
.name = "<unknown client>"};
- auto deathNotifier = std::make_shared<OverrideProcessInfoDeathNotifier>(
- client, ref<ResourceManagerService>(), clientInfo, mDeathRecipient.get());
+ auto deathNotifier = DeathNotifier::Create(
+ client, ref<ResourceManagerService>(), clientInfo, true);
mProcessInfoOverrideMap.emplace(pid, ProcessInfoOverride{deathNotifier, client});
@@ -944,21 +832,19 @@
MediaResource::SubType::kSwVideoCodec,
MediaResource::SubType::kHwImageCodec,
MediaResource::SubType::kSwImageCodec}) {
- std::shared_ptr<IResourceManagerClient> client;
- uid_t uid = 0;
- if (getBiggestClientPendingRemoval_l(pid, type, subType, uid, &client)) {
- targetClients.emplace_back(pid, uid, client);
+ ClientInfo clientInfo;
+ if (getBiggestClientPendingRemoval_l(pid, type, subType, clientInfo)) {
+ targetClients.emplace_back(clientInfo);
continue;
}
}
break;
// Non-codec resources are shared by audio, video and image codecs (no subtype).
default:
- std::shared_ptr<IResourceManagerClient> client;
- uid_t uid = 0;
+ ClientInfo clientInfo;
if (getBiggestClientPendingRemoval_l(pid, type,
- MediaResource::SubType::kUnspecifiedSubType, uid, &client)) {
- targetClients.emplace_back(pid, uid, client);
+ MediaResource::SubType::kUnspecifiedSubType, clientInfo)) {
+ targetClients.emplace_back(clientInfo);
}
break;
}
@@ -1000,7 +886,7 @@
clientsInfo.clear();
return false;
}
- clientsInfo.emplace_back(pid, info.uid, info.client);
+ clientsInfo.emplace_back(pid, info.uid, info.clientId);
}
}
}
@@ -1015,15 +901,13 @@
// - Find the bigegst client (with required resources) from that process.
bool ResourceManagerService::getLowestPriorityBiggestClient_l(
const ResourceRequestInfo& resourceRequestInfo,
- ClientInfo& clientsInfo) {
+ ClientInfo& clientInfo) {
int callingPid = resourceRequestInfo.mCallingPid;
MediaResource::Type type = resourceRequestInfo.mResource->type;
MediaResource::SubType subType = resourceRequestInfo.mResource->subType;
int lowestPriorityPid;
int lowestPriority;
int callingPriority;
- uid_t uid = 0;
- std::shared_ptr<IResourceManagerClient> client;
if (!getPriority_l(callingPid, &callingPriority)) {
ALOGE("%s: can't get process priority for pid %d", __func__, callingPid);
@@ -1038,13 +922,10 @@
return false;
}
- if (!getBiggestClient_l(lowestPriorityPid, type, subType, uid, &client)) {
+ if (!getBiggestClient_l(lowestPriorityPid, type, subType, clientInfo)) {
return false;
}
- clientsInfo.mPid = lowestPriorityPid;
- clientsInfo.mUid = uid;
- clientsInfo.mClient = client;
ALOGI("%s: CallingProcess(%d:%d) will reclaim from the lowestPriorityProcess(%d:%d)",
__func__, callingPid, callingPriority, lowestPriorityPid, lowestPriority);
return true;
@@ -1097,15 +978,12 @@
}
bool ResourceManagerService::getBiggestClientPendingRemoval_l(int pid, MediaResource::Type type,
- MediaResource::SubType subType, uid_t& uid,
- std::shared_ptr<IResourceManagerClient> *client) {
- return getBiggestClient_l(pid, type, subType, uid, client, true /* pendingRemovalOnly */);
+ MediaResource::SubType subType, ClientInfo& clientInfo) {
+ return getBiggestClient_l(pid, type, subType, clientInfo, true /* pendingRemovalOnly */);
}
bool ResourceManagerService::getBiggestClient_l(int pid, MediaResource::Type type,
- MediaResource::SubType subType, uid_t& uid,
- std::shared_ptr<IResourceManagerClient> *client,
- bool pendingRemovalOnly) {
+ MediaResource::SubType subType, ClientInfo& clientInfo, bool pendingRemovalOnly) {
PidResourceInfosMap::iterator found = mMap.find(pid);
if (found == mMap.end()) {
ALOGE_IF(!pendingRemovalOnly,
@@ -1113,7 +991,8 @@
return false;
}
- std::shared_ptr<IResourceManagerClient> clientTemp;
+ uid_t uid = -1;
+ int64_t clientId = -1;
uint64_t largestValue = 0;
const ResourceInfos& infos = found->second;
for (const auto& [id, info] : infos) {
@@ -1126,21 +1005,23 @@
if (hasResourceType(type, subType, resource)) {
if (resource.value > largestValue) {
largestValue = resource.value;
- clientTemp = info.client;
+ clientId = info.clientId;
uid = info.uid;
}
}
}
}
- if (clientTemp == NULL) {
+ if (clientId == -1) {
ALOGE_IF(!pendingRemovalOnly,
"getBiggestClient_l: can't find resource type %s and subtype %s for pid %d",
asString(type), asString(subType), pid);
return false;
}
- *client = clientTemp;
+ clientInfo.mPid = pid;
+ clientInfo.mUid = uid;
+ clientInfo.mClientId = clientId;
return true;
}
diff --git a/services/mediaresourcemanager/ResourceManagerService.h b/services/mediaresourcemanager/ResourceManagerService.h
index de7e4a3..e22a6b3 100644
--- a/services/mediaresourcemanager/ResourceManagerService.h
+++ b/services/mediaresourcemanager/ResourceManagerService.h
@@ -30,9 +30,10 @@
#include <utils/String8.h>
#include <utils/threads.h>
+#include "ResourceManagerServiceUtils.h"
+
namespace android {
-class DeathNotifier;
class ResourceObserverService;
class ServiceLog;
struct ProcessInfoInterface;
@@ -46,57 +47,6 @@
using ::aidl::android::media::ClientInfoParcel;
using ::aidl::android::media::ClientConfigParcel;
-typedef std::map<std::tuple<
- MediaResource::Type, MediaResource::SubType, std::vector<uint8_t>>,
- MediaResourceParcel> ResourceList;
-
-struct ResourceInfo {
- uid_t uid;
- int64_t clientId;
- std::string name;
- std::shared_ptr<IResourceManagerClient> client;
- std::shared_ptr<DeathNotifier> deathNotifier = nullptr;
- ResourceList resources;
- bool pendingRemoval{false};
-};
-
-/*
- * Resource request info that encapsulates
- * - the calling/requesting process pid.
- * - the resource requesting (to be reclaimed from others)
- */
-struct ResourceRequestInfo {
- // uid of the calling/requesting process.
- int mCallingPid = -1;
- // resources requested.
- const ::aidl::android::media::MediaResourceParcel* mResource;
-};
-
-/*
- * Structure that defines the Client - a possible target to relcaim from.
- * This encapsulates pid, uid of the process and the client.
- * based on the reclaim policy.
- */
-struct ClientInfo {
- // pid of the process.
- pid_t mPid;
- // uid of the process.
- uid_t mUid;
- // Client to relcaim from.
- std::shared_ptr<::aidl::android::media::IResourceManagerClient> mClient;
- ClientInfo(
- pid_t pid = -1,
- uid_t uid = -1,
- const std::shared_ptr<::aidl::android::media::IResourceManagerClient>& client = nullptr)
- : mPid(pid),
- mUid(uid),
- mClient(client) {
- }
-};
-
-typedef std::map<int64_t, ResourceInfo> ResourceInfos;
-typedef std::map<int, ResourceInfos> PidResourceInfosMap;
-
class ResourceManagerService : public BnResourceManagerService {
public:
struct SystemCallbackInterface : public RefBase {
@@ -109,13 +59,20 @@
static char const *getServiceName() { return "media.resource_manager"; }
static void instantiate();
- virtual inline binder_status_t dump(
+ // Static creation methods.
+ static std::shared_ptr<ResourceManagerService> Create();
+ static std::shared_ptr<ResourceManagerService> Create(
+ const sp<ProcessInfoInterface>& processInfo,
+ const sp<SystemCallbackInterface>& systemResource);
+
+ virtual binder_status_t dump(
int /*fd*/, const char** /*args*/, uint32_t /*numArgs*/);
ResourceManagerService();
explicit ResourceManagerService(const sp<ProcessInfoInterface> &processInfo,
const sp<SystemCallbackInterface> &systemResource);
virtual ~ResourceManagerService();
+
void setObserverService(const std::shared_ptr<ResourceObserverService>& observerService);
// IResourceManagerService interface
@@ -158,6 +115,7 @@
private:
friend class ResourceManagerServiceTest;
+ friend class ResourceManagerServiceTestBase;
friend class DeathNotifier;
friend class OverrideProcessInfoDeathNotifier;
@@ -183,12 +141,12 @@
// Returns false with no change to client if there are no clients holding resources of this
// type.
bool getBiggestClient_l(int pid, MediaResource::Type type, MediaResource::SubType subType,
- uid_t& uid, std::shared_ptr<IResourceManagerClient> *client,
+ ClientInfo& clientsInfo,
bool pendingRemovalOnly = false);
// Same method as above, but with pendingRemovalOnly as true.
bool getBiggestClientPendingRemoval_l(int pid, MediaResource::Type type,
- MediaResource::SubType subType, uid_t& uid,
- std::shared_ptr<IResourceManagerClient>* client);
+ MediaResource::SubType subType,
+ ClientInfo& clientsInfo);
// A helper function that returns true if the callingPid has higher priority than pid.
// Returns false otherwise.
@@ -199,11 +157,8 @@
void getClientForResource_l(const ResourceRequestInfo& resourceRequestInfo,
std::vector<ClientInfo>& clientsInfo);
- void onFirstAdded(const MediaResourceParcel& res, const ResourceInfo& clientInfo);
- void onLastRemoved(const MediaResourceParcel& res, const ResourceInfo& clientInfo);
-
- // Merge r2 into r1
- void mergeResources(MediaResourceParcel& r1, const MediaResourceParcel& r2);
+ void onFirstAdded(const MediaResourceParcel& res, uid_t uid);
+ void onLastRemoved(const MediaResourceParcel& res, uid_t uid);
// Get priority from process's pid
bool getPriority_l(int pid, int* priority);
@@ -216,6 +171,12 @@
const std::vector<ClientInfo>& targetClients,
bool reclaimed);
+ // Get the client for given pid and the clientId from the map
+ std::shared_ptr<IResourceManagerClient> getClient(int pid, const int64_t& clientId) const;
+
+ // Remove the client for given pid and the clientId from the map
+ bool removeClient(int pid, const int64_t& clientId);
+
// The following utility functions are used only for testing by ResourceManagerServiceTest
// Gets lowest priority process that has the specified resource type.
// Returns false if failed. The output parameters will remain unchanged if failed.
@@ -234,7 +195,6 @@
bool mSupportsMultipleSecureCodecs;
bool mSupportsSecureWithNonSecureCodec;
int32_t mCpuBoostCount;
- ::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
struct ProcessInfoOverride {
std::shared_ptr<DeathNotifier> deathNotifier = nullptr;
std::shared_ptr<IResourceManagerClient> client;
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
diff --git a/services/mediaresourcemanager/ResourceManagerServiceUtils.h b/services/mediaresourcemanager/ResourceManagerServiceUtils.h
index bbc26de..ac1e410 100644
--- a/services/mediaresourcemanager/ResourceManagerServiceUtils.h
+++ b/services/mediaresourcemanager/ResourceManagerServiceUtils.h
@@ -19,10 +19,143 @@
#define ANDROID_MEDIA_RESOURCEMANAGERSERVICEUTILS_H_
#include <vector>
+
+#include <aidl/android/media/BnResourceManagerService.h>
+#include <media/MediaResource.h>
#include <utils/String8.h>
namespace android {
+class ResourceManagerService;
+
+/*
+ * Death Notifier to track IResourceManagerClient's death.
+ */
+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<::aidl::android::media::IResourceManagerClient>& client,
+ const std::weak_ptr<ResourceManagerService>& service,
+ const ::aidl::android::media::ClientInfoParcel& clientInfo,
+ bool overrideProcessInfo = false);
+
+ DeathNotifier(const std::shared_ptr<::aidl::android::media::IResourceManagerClient>& client,
+ const std::weak_ptr<ResourceManagerService>& service,
+ const ::aidl::android::media::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<::aidl::android::media::IResourceManagerClient> mClient;
+ std::weak_ptr<ResourceManagerService> mService;
+ const ::aidl::android::media::ClientInfoParcel mClientInfo;
+ BinderDiedContext* mCookie;
+ ::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
+};
+
+class OverrideProcessInfoDeathNotifier : public DeathNotifier {
+public:
+ OverrideProcessInfoDeathNotifier(
+ const std::shared_ptr<::aidl::android::media::IResourceManagerClient>& client,
+ const std::weak_ptr<ResourceManagerService>& service,
+ const ::aidl::android::media::ClientInfoParcel& clientInfo)
+ : DeathNotifier(client, service, clientInfo) {}
+
+ virtual ~OverrideProcessInfoDeathNotifier() {}
+
+ virtual void binderDied();
+};
+
+// A map of tuple(type, sub-type, id) and the resource parcel.
+typedef std::map<std::tuple<
+ MediaResource::Type, MediaResource::SubType, std::vector<uint8_t>>,
+ ::aidl::android::media::MediaResourceParcel> ResourceList;
+
+// Encapsulation for Resource Info, that contains
+// - pid of the app
+// - uid of the app
+// - client id
+// - name of the client (specifically for the codec)
+// - the client associted with it
+// - death notifier for the (above) client
+// - list of resources associated with it
+// - A flag that marks whether this resource is pending to be removed.
+struct ResourceInfo {
+ pid_t pid;
+ uid_t uid;
+ int64_t clientId;
+ std::string name;
+ std::shared_ptr<::aidl::android::media::IResourceManagerClient> client;
+ std::shared_ptr<DeathNotifier> deathNotifier = nullptr;
+ ResourceList resources;
+ bool pendingRemoval{false};
+};
+
+/*
+ * Resource request info that encapsulates
+ * - the calling/requesting process pid.
+ * - the resource requesting (to be reclaimed from others)
+ */
+struct ResourceRequestInfo {
+ // pid of the calling/requesting process.
+ int mCallingPid = -1;
+ // resources requested.
+ const ::aidl::android::media::MediaResourceParcel* mResource;
+};
+
+/*
+ * Structure that defines the Client - a possible target to relcaim from.
+ * This encapsulates pid, uid of the process and the client id
+ * based on the reclaim policy.
+ */
+struct ClientInfo {
+ // pid of the process.
+ pid_t mPid = -1;
+ // uid of the process.
+ uid_t mUid = -1;
+ // Client Id.
+ int64_t mClientId = -1;
+ ClientInfo(pid_t pid = -1, uid_t uid = -1, const int64_t& clientId = -1)
+ : mPid(pid), mUid(uid), mClientId(clientId) {}
+};
+
+// Map of Resource information index through the client id.
+typedef std::map<int64_t, ResourceInfo> ResourceInfos;
+
+// Map of Resource information indexed through the process id.
+typedef std::map<int, ResourceInfos> PidResourceInfosMap;
+
// templated function to stringify the given vector of items.
template <typename T>
String8 getString(const std::vector<T>& items) {
@@ -37,15 +170,15 @@
//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);
//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);
//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);
// Return modifiable list of ResourceInfo for a given process (look up by pid)
// from the map of ResourceInfos.
@@ -54,8 +187,13 @@
// Return modifiable ResourceInfo for a given process (look up by pid)
// 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);
+ResourceInfo& getResourceInfoForEdit(
+ const aidl::android::media::ClientInfoParcel& clientInfo,
+ const std::shared_ptr<aidl::android::media::IResourceManagerClient>& client,
+ ResourceInfos& infos);
+
+// Merge resources from r2 into r1.
+void mergeResources(MediaResourceParcel& r1, const MediaResourceParcel& r2);
} // namespace android
diff --git a/services/mediaresourcemanager/fuzzer/mediaresourcemanager_fuzzer.cpp b/services/mediaresourcemanager/fuzzer/mediaresourcemanager_fuzzer.cpp
index 6fa9831..643a4e5 100644
--- a/services/mediaresourcemanager/fuzzer/mediaresourcemanager_fuzzer.cpp
+++ b/services/mediaresourcemanager/fuzzer/mediaresourcemanager_fuzzer.cpp
@@ -208,9 +208,9 @@
return nullptr;
}
- shared_ptr<ResourceManagerService> mService =
- ::ndk::SharedRefBase::make<ResourceManagerService>(new TestProcessInfo(),
- new TestSystemCallback());
+ shared_ptr<ResourceManagerService> mService = ResourceManagerService::Create(
+ new TestProcessInfo(),
+ new TestSystemCallback());
FuzzedDataProvider* mFuzzedDataProvider = nullptr;
};
diff --git a/services/mediaresourcemanager/test/Android.bp b/services/mediaresourcemanager/test/Android.bp
index de24e1e..f903c62 100644
--- a/services/mediaresourcemanager/test/Android.bp
+++ b/services/mediaresourcemanager/test/Android.bp
@@ -20,7 +20,6 @@
"libmedia",
"libmediautils",
"libutils",
- "libmediautils",
"libstats_media_metrics",
"libstatspull",
"libstatssocket",
diff --git a/services/mediaresourcemanager/test/ResourceManagerServiceTestUtils.h b/services/mediaresourcemanager/test/ResourceManagerServiceTestUtils.h
index 474ff0f..52d82b8 100644
--- a/services/mediaresourcemanager/test/ResourceManagerServiceTestUtils.h
+++ b/services/mediaresourcemanager/test/ResourceManagerServiceTestUtils.h
@@ -207,8 +207,7 @@
// silently ignored.
ABinderProcess_startThreadPool();
mSystemCB = new TestSystemCallback();
- mService = ::ndk::SharedRefBase::make<ResourceManagerService>(
- new TestProcessInfo, mSystemCB);
+ mService = ResourceManagerService::Create(new TestProcessInfo, mSystemCB);
mTestClient1 = ::ndk::SharedRefBase::make<TestClient>(kTestPid1, kTestUid1, mService);
mTestClient2 = ::ndk::SharedRefBase::make<TestClient>(kTestPid2, kTestUid2, mService);
mTestClient3 = ::ndk::SharedRefBase::make<TestClient>(kTestPid2, kTestUid2, mService);
diff --git a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
index 7452275..8f05b13 100644
--- a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
+++ b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
@@ -495,8 +495,8 @@
EXPECT_EQ(2u, targetClients.size());
// (OK to require ordering in clients[], as the pid map is sorted)
- EXPECT_EQ(mTestClient3, targetClients[0].mClient);
- EXPECT_EQ(mTestClient1, targetClients[1].mClient);
+ EXPECT_EQ(getId(mTestClient3), targetClients[0].mClientId);
+ EXPECT_EQ(getId(mTestClient1), targetClients[1].mClientId);
}
void testReclaimResourceSecure() {
@@ -775,7 +775,7 @@
// kTestPid1 is the lowest priority process with MediaResource::Type::kGraphicMemory.
// mTestClient1 has the largest MediaResource::Type::kGraphicMemory within kTestPid1.
- EXPECT_EQ(mTestClient1, clientInfo.mClient);
+ EXPECT_EQ(getId(mTestClient1), clientInfo.mClientId);
}
void testGetLowestPriorityPid() {