drm: refactor resourcemanager death handling
media.resource.manager Binder death notification is refactored as it:
- doesn't connect with the resource.manager upon death.
So, the following changes are made with this CL:
- Reconnect with the resource.manager upon death
- Re-register all the resources, so that resource.manager
will have all the resource information to help with
drm session reclaim.
- Replacing the deprecated API AServiceManager_getService
with AServiceManager_waitForService.
Bug: 284031542
Test: atest android.media.misc.cts.ResourceManagerTest
Test: atest android.resourcemanager.cts.ResourceManagerHostJUnit4Test
Test: DrmSessionManagerTest
Test: DrmSessionManager_test
Test: MediaDrmClearkeyTest.testGetNumberOfSessions
Merged-In: If0468444741a076321dbf3666628dc89833f2dc9
Change-Id: If0468444741a076321dbf3666628dc89833f2dc9
diff --git a/drm/libmediadrm/DrmSessionManager.cpp b/drm/libmediadrm/DrmSessionManager.cpp
index 301538f..6744e25 100644
--- a/drm/libmediadrm/DrmSessionManager.cpp
+++ b/drm/libmediadrm/DrmSessionManager.cpp
@@ -36,13 +36,6 @@
using aidl::android::media::MediaResourceParcel;
using aidl::android::media::ClientInfoParcel;
-namespace {
-void ResourceManagerServiceDied(void* cookie) {
- auto thiz = static_cast<DrmSessionManager*>(cookie);
- thiz->binderDied();
-}
-}
-
using ::ndk::ScopedAStatus;
static String8 GetSessionIdString(const Vector<uint8_t> &sessionId) {
@@ -60,6 +53,12 @@
return vec;
}
+static Vector<uint8_t> toAndroidVec(const std::vector<uint8_t>& array) {
+ Vector<uint8_t> vec;
+ vec.appendArray(array.data(), array.size());
+ return vec;
+}
+
static std::vector<MediaResourceParcel> toResourceVec(
const Vector<uint8_t> &sessionId, int64_t value) {
using Type = aidl::android::media::MediaResourceType;
@@ -72,11 +71,6 @@
return resources;
}
-static std::shared_ptr<IResourceManagerService> getResourceManagerService() {
- ::ndk::SpAIBinder binder(AServiceManager_getService("media.resource_manager"));
- return IResourceManagerService::fromBinder(binder);
-}
-
bool isEqualSessionId(const Vector<uint8_t> &sessionId1, const Vector<uint8_t> &sessionId2) {
if (sessionId1.size() != sessionId2.size()) {
return false;
@@ -96,16 +90,15 @@
}
DrmSessionManager::DrmSessionManager()
- : DrmSessionManager(getResourceManagerService()) {
+ : DrmSessionManager(nullptr) {
}
DrmSessionManager::DrmSessionManager(const std::shared_ptr<IResourceManagerService> &service)
: mService(service),
- mInitialized(false),
- mDeathRecipient(AIBinder_DeathRecipient_new(ResourceManagerServiceDied)) {
- if (mService == NULL) {
- ALOGE("Failed to init ResourceManagerService");
- }
+ mDeathRecipient(::ndk::ScopedAIBinder_DeathRecipient(
+ AIBinder_DeathRecipient_new(ResourceManagerServiceDied))) {
+ // Setting callback notification when DeathRecipient gets deleted.
+ AIBinder_DeathRecipient_setOnUnlinked(mDeathRecipient.get(), BinderUnlinkedCallback);
}
DrmSessionManager::~DrmSessionManager() {
@@ -114,14 +107,64 @@
}
}
-void DrmSessionManager::init() {
+status_t DrmSessionManager::init() {
Mutex::Autolock lock(mLock);
- if (mInitialized) {
+ getResourceManagerService_l();
+ if (mService == nullptr) {
+ ALOGE("Failed to init ResourceManagerService");
+ return DEAD_OBJECT;
+ }
+
+ return OK;
+}
+
+void DrmSessionManager::getResourceManagerService_l() {
+ if (mService != nullptr) {
return;
}
- mInitialized = true;
- if (mService != NULL) {
- AIBinder_linkToDeath(mService->asBinder().get(), mDeathRecipient.get(), this);
+
+ // Get binder interface to resource manager.
+ ::ndk::SpAIBinder binder(AServiceManager_waitForService("media.resource_manager"));
+ mService = IResourceManagerService::fromBinder(binder);
+ if (mService == nullptr) {
+ ALOGE("Failed to get ResourceManagerService");
+ return;
+ }
+
+ // Create the context that is passed as cookie to the binder death notification.
+ // The context gets deleted at BinderUnlinkedCallback.
+ BinderDiedContext* context = new BinderDiedContext{
+ .mDrmSessionManager = wp<DrmSessionManager>::fromExisting(this)};
+ // Register for the callbacks by linking to death notification.
+ AIBinder_linkToDeath(mService->asBinder().get(), mDeathRecipient.get(), context);
+
+ // If the RM was restarted, re-register all the resources.
+ if (mBinderDied) {
+ reRegisterAllResources_l();
+ mBinderDied = false;
+ }
+}
+
+void DrmSessionManager::reRegisterAllResources_l() {
+ if (mSessionMap.empty()) {
+ // Nothing to register.
+ ALOGV("No resources to add");
+ return;
+ }
+
+ if (mService == nullptr) {
+ ALOGW("Service isn't available");
+ return;
+ }
+
+ // Go through the session map and re-register all the resources for those sessions.
+ for (SessionInfoMap::const_iterator iter = mSessionMap.begin();
+ iter != mSessionMap.end(); ++iter) {
+ ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(iter->second.pid),
+ .uid = static_cast<int32_t>(iter->second.uid),
+ .id = iter->second.clientId};
+ mService->addResource(clientInfo, iter->second.drm,
+ toResourceVec(toAndroidVec(iter->first), iter->second.resourceValue));
}
}
@@ -137,7 +180,7 @@
}
static int64_t clientId = 0;
- mSessionMap[toStdVec(sessionId)] = (SessionInfo){pid, uid, clientId};
+ mSessionMap[toStdVec(sessionId)] = (SessionInfo){pid, uid, clientId, drm, INT64_MAX};
ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(pid),
.uid = static_cast<int32_t>(uid),
.id = clientId++};
@@ -154,6 +197,7 @@
}
auto info = it->second;
+ info.resourceValue = -1;
ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(info.pid),
.uid = static_cast<int32_t>(info.uid),
.id = info.clientId};
@@ -215,7 +259,31 @@
void DrmSessionManager::binderDied() {
ALOGW("ResourceManagerService died.");
Mutex::Autolock lock(mLock);
- mService.reset();
+ mService = nullptr;
+ mBinderDied = true;
+ // start an async operation that will reconnect with the RM and
+ // re-registers all the resources.
+ mGetServiceFuture = std::async(std::launch::async, [this] { getResourceManagerService(); });
+}
+
+void DrmSessionManager::ResourceManagerServiceDied(void* cookie) {
+ BinderDiedContext* context = reinterpret_cast<BinderDiedContext*>(cookie);
+
+ // Validate the context and check if the DrmSessionManager object is still in scope.
+ if (context != nullptr) {
+ sp<DrmSessionManager> thiz = context->mDrmSessionManager.promote();
+ if (thiz != nullptr) {
+ thiz->binderDied();
+ } else {
+ ALOGI("DrmSessionManager is out of scope already");
+ }
+ }
+}
+
+void DrmSessionManager::BinderUnlinkedCallback(void* cookie) {
+ BinderDiedContext* context = reinterpret_cast<BinderDiedContext*>(cookie);
+ // Since we don't need the context anymore, we are deleting it now.
+ delete context;
}
} // namespace android
diff --git a/drm/libmediadrm/include/mediadrm/DrmSessionManager.h b/drm/libmediadrm/include/mediadrm/DrmSessionManager.h
index c56bf01..025261d 100644
--- a/drm/libmediadrm/include/mediadrm/DrmSessionManager.h
+++ b/drm/libmediadrm/include/mediadrm/DrmSessionManager.h
@@ -27,8 +27,10 @@
#include <utils/threads.h>
#include <utils/Vector.h>
+#include <future>
#include <map>
#include <memory>
+#include <set>
#include <utility>
#include <vector>
@@ -38,6 +40,7 @@
using aidl::android::media::IResourceManagerClient;
using aidl::android::media::IResourceManagerService;
+using aidl::android::media::MediaResourceParcel;
bool isEqualSessionId(const Vector<uint8_t> &sessionId1, const Vector<uint8_t> &sessionId2);
@@ -45,6 +48,9 @@
pid_t pid;
uid_t uid;
int64_t clientId;
+ std::shared_ptr<IResourceManagerClient> drm;
+ int64_t resourceValue;
+
};
typedef std::map<std::vector<uint8_t>, SessionInfo> SessionInfoMap;
@@ -66,20 +72,52 @@
size_t getSessionCount() const;
bool containsSession(const Vector<uint8_t>& sessionId) const;
- // implements DeathRecipient
- void binderDied();
-
protected:
virtual ~DrmSessionManager();
private:
- void init();
+ status_t init();
- std::shared_ptr<IResourceManagerService> mService;
+ // To set up the binder interface with the resource manager service.
+ void getResourceManagerService() {
+ Mutex::Autolock lock(mLock);
+ getResourceManagerService_l();
+ }
+ void getResourceManagerService_l();
+
+ // To add/register all the resources currently added/registered with
+ // the ResourceManagerService.
+ // This function will be called right after the death of the Resource
+ // Manager to make sure that the newly started ResourceManagerService
+ // knows about the current resource usage.
+ void reRegisterAllResources_l();
+
+ // For binder death handling
+ static void ResourceManagerServiceDied(void* cookie);
+ static void BinderUnlinkedCallback(void* cookie);
+ void binderDied();
+
+ // 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 DrmSessionManager,
+ // before deferencing it upon the binder death.
+ struct BinderDiedContext {
+ wp<DrmSessionManager> mDrmSessionManager;
+ };
+
+ std::shared_ptr<IResourceManagerService> mService = nullptr;
mutable Mutex mLock;
SessionInfoMap mSessionMap;
- bool mInitialized;
+ bool mBinderDied = false;
::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
+ /**
+ * Reconnecting with the ResourceManagerService, after its binder interface dies,
+ * is done asynchronously. It will also make sure that, all the resources
+ * asssociated with this DrmSessionManager are added with the new instance
+ * of the ResourceManagerService to persist the state of resources.
+ * We must store the reference of the furture to guarantee real asynchronous operation.
+ */
+ std::future<void> mGetServiceFuture;
DISALLOW_EVIL_CONSTRUCTORS(DrmSessionManager);
};
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index b02a1e8..457c625 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -448,17 +448,18 @@
void MediaCodec::ResourceManagerServiceProxy::reRegisterAllResources_l() {
if (mMediaResourceParcel.empty()) {
- ALOGV("%s:%d:%p No resources to add", __func__, __LINE__, this);
+ ALOGV("No resources to add");
+ return;
+ }
+
+ if (mService == nullptr) {
+ ALOGW("Service isn't available");
return;
}
std::vector<MediaResourceParcel> resources;
std::copy(mMediaResourceParcel.begin(), mMediaResourceParcel.end(),
std::back_inserter(resources));
- if (mService == nullptr) {
- ALOGW("%s:%d:%p Serice isn't available", __func__, __LINE__, this);
- return;
- }
ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(mPid),
.uid = static_cast<int32_t>(mUid),
.id = getId(mClient),
@@ -491,7 +492,7 @@
std::scoped_lock lock{mLock};
std::shared_ptr<IResourceManagerService> service = getService_l();
if (service == nullptr) {
- ALOGW("%s:%d:%p Serice isn't available", __func__, __LINE__, this);
+ ALOGW("Service isn't available");
return;
}
std::vector<MediaResourceParcel> resources;
@@ -509,7 +510,7 @@
std::scoped_lock lock{mLock};
std::shared_ptr<IResourceManagerService> service = getService_l();
if (service == nullptr) {
- ALOGW("%s:%d:%p Serice isn't available", __func__, __LINE__, this);
+ ALOGW("Service isn't available");
return;
}
std::vector<MediaResourceParcel> resources;
@@ -526,7 +527,7 @@
std::scoped_lock lock{mLock};
std::shared_ptr<IResourceManagerService> service = getService_l();
if (service == nullptr) {
- ALOGW("%s:%d:%p Serice isn't available", __func__, __LINE__, this);
+ ALOGW("Service isn't available");
return;
}
ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(mPid),
@@ -541,7 +542,7 @@
std::scoped_lock lock{mLock};
std::shared_ptr<IResourceManagerService> service = getService_l();
if (service == nullptr) {
- ALOGW("%s:%d:%p Serice isn't available", __func__, __LINE__, this);
+ ALOGW("Service isn't available");
return;
}
ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(mPid),
@@ -557,7 +558,7 @@
std::scoped_lock lock{mLock};
std::shared_ptr<IResourceManagerService> service = getService_l();
if (service == nullptr) {
- ALOGW("%s:%d:%p Service isn't available", __func__, __LINE__, this);
+ ALOGW("Service isn't available");
return false;
}
bool success;
@@ -573,7 +574,7 @@
std::scoped_lock lock{mLock};
std::shared_ptr<IResourceManagerService> service = getService_l();
if (service == nullptr) {
- ALOGW("%s:%d:%p Serice isn't available", __func__, __LINE__, this);
+ ALOGW("Service isn't available");
return;
}
ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(mPid),
@@ -588,7 +589,7 @@
std::scoped_lock lock{mLock};
std::shared_ptr<IResourceManagerService> service = getService_l();
if (service == nullptr) {
- ALOGW("%s:%d:%p Serice isn't available", __func__, __LINE__, this);
+ ALOGW("Service isn't available");
return;
}
clientConfig.clientInfo.pid = static_cast<int32_t>(mPid);
@@ -603,7 +604,7 @@
std::scoped_lock lock{mLock};
std::shared_ptr<IResourceManagerService> service = getService_l();
if (service == nullptr) {
- ALOGW("%s:%d:%p Serice isn't available", __func__, __LINE__, this);
+ ALOGW("Service isn't available");
return;
}
clientConfig.clientInfo.pid = static_cast<int32_t>(mPid);
@@ -618,7 +619,7 @@
std::scoped_lock lock{mLock};
std::shared_ptr<IResourceManagerService> service = getService_l();
if (service == nullptr) {
- ALOGW("%s:%d:%p Serice isn't available", __func__, __LINE__, this);
+ ALOGW("Service isn't available");
return;
}
clientConfig.clientInfo.pid = static_cast<int32_t>(mPid);