Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 323711ff authored by Girish's avatar Girish
Browse files

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
parent 429f8598
Loading
Loading
Loading
Loading
+93 −25
Original line number Diff line number Diff line
@@ -36,13 +36,6 @@ namespace android {
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 @@ static std::vector<Byte> toStdVec(const Vector<uint8_t> &vector) {
    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 @@ static std::vector<MediaResourceParcel> toResourceVec(
    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 @@ sp<DrmSessionManager> DrmSessionManager::Instance() {
}

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 @@ DrmSessionManager::~DrmSessionManager() {
    }
}

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 @@ void DrmSessionManager::addSession(int pid,
    }

    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 @@ void DrmSessionManager::useSession(const Vector<uint8_t> &sessionId) {
    }

    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 @@ bool DrmSessionManager::containsSession(const Vector<uint8_t>& sessionId) const
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
+44 −6
Original line number Diff line number Diff line
@@ -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 @@ class DrmSessionManagerTest;

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 @@ struct SessionInfo {
    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 @@ struct DrmSessionManager : public RefBase {
    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();

    // 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();

    std::shared_ptr<IResourceManagerService> mService;
    // 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);
};
+15 −14
Original line number Diff line number Diff line
@@ -448,17 +448,18 @@ std::shared_ptr<IResourceManagerService> MediaCodec::ResourceManagerServiceProxy

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;
    }

    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);
        ALOGW("Service isn't available");
        return;
    }

    std::vector<MediaResourceParcel> resources;
    std::copy(mMediaResourceParcel.begin(), mMediaResourceParcel.end(),
              std::back_inserter(resources));
    ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(mPid),
                                .uid = static_cast<int32_t>(mUid),
                                .id = getId(mClient),
@@ -491,7 +492,7 @@ void MediaCodec::ResourceManagerServiceProxy::addResource(
    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 @@ void MediaCodec::ResourceManagerServiceProxy::removeResource(
    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 @@ void MediaCodec::ResourceManagerServiceProxy::removeClient() {
    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 @@ void MediaCodec::ResourceManagerServiceProxy::markClientForPendingRemoval() {
    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 @@ bool MediaCodec::ResourceManagerServiceProxy::reclaimResource(
    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 @@ void MediaCodec::ResourceManagerServiceProxy::notifyClientCreated() {
    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 @@ void MediaCodec::ResourceManagerServiceProxy::notifyClientStarted(
    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 @@ void MediaCodec::ResourceManagerServiceProxy::notifyClientStopped(
    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 @@ void MediaCodec::ResourceManagerServiceProxy::notifyClientConfigChanged(
    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);