From 5c3da20ddde6d17c3ab3cff7f7ca19f4f484f812 Mon Sep 17 00:00:00 2001 From: Ronghua Wu Date: Sun, 22 Feb 2015 08:45:28 -0800 Subject: drm: use DrmSessionManager for session resource managing. Bug: 19265536 Change-Id: Ie35184f99c51e7bd94d7c826ffb8e89040a81905 --- media/libmediaplayerservice/Drm.cpp | 74 +++++++++++++++++++++- media/libmediaplayerservice/Drm.h | 3 + media/libmediaplayerservice/DrmSessionManager.cpp | 56 ++++++++++++---- media/libmediaplayerservice/DrmSessionManager.h | 2 + media/libmediaplayerservice/ProcessInfoInterface.h | 2 +- .../tests/DrmSessionManager_test.cpp | 21 ++++-- 6 files changed, 135 insertions(+), 23 deletions(-) (limited to 'media') diff --git a/media/libmediaplayerservice/Drm.cpp b/media/libmediaplayerservice/Drm.cpp index 73f1a2a..d4f6fab 100644 --- a/media/libmediaplayerservice/Drm.cpp +++ b/media/libmediaplayerservice/Drm.cpp @@ -23,6 +23,8 @@ #include "Drm.h" +#include "DrmSessionClientInterface.h" +#include "DrmSessionManager.h" #include #include #include @@ -33,6 +35,10 @@ namespace android { +static inline int getCallingPid() { + return IPCThreadState::self()->getCallingPid(); +} + static bool checkPermission(const char* permissionString) { #ifndef HAVE_ANDROID_OS return true; @@ -57,14 +63,41 @@ static bool operator<(const Vector &lhs, const Vector &rhs) { return memcmp((void *)lhs.array(), (void *)rhs.array(), rhs.size()) < 0; } +struct DrmSessionClient : public DrmSessionClientInterface { + DrmSessionClient(Drm* drm) : mDrm(drm) {} + + virtual bool reclaimSession(const Vector& sessionId) { + sp drm = mDrm.promote(); + if (drm == NULL) { + return true; + } + status_t err = drm->closeSession(sessionId); + if (err != OK) { + return false; + } + drm->sendEvent(DrmPlugin::kDrmPluginEventSessionReclaimed, 0, &sessionId, NULL); + return true; + } + +protected: + virtual ~DrmSessionClient() {} + +private: + wp mDrm; + + DISALLOW_EVIL_CONSTRUCTORS(DrmSessionClient); +}; + Drm::Drm() : mInitCheck(NO_INIT), + mDrmSessionClient(new DrmSessionClient(this)), mListener(NULL), mFactory(NULL), mPlugin(NULL) { } Drm::~Drm() { + DrmSessionManager::Instance()->removeDrm(mDrmSessionClient); delete mPlugin; mPlugin = NULL; closeFactory(); @@ -289,7 +322,18 @@ status_t Drm::openSession(Vector &sessionId) { return -EINVAL; } - return mPlugin->openSession(sessionId); + status_t err = mPlugin->openSession(sessionId); + if (err == ERROR_DRM_RESOURCE_BUSY) { + bool retry = false; + retry = DrmSessionManager::Instance()->reclaimSession(getCallingPid()); + if (retry) { + err = mPlugin->openSession(sessionId); + } + } + if (err == OK) { + DrmSessionManager::Instance()->addSession(getCallingPid(), mDrmSessionClient, sessionId); + } + return err; } status_t Drm::closeSession(Vector const &sessionId) { @@ -303,7 +347,11 @@ status_t Drm::closeSession(Vector const &sessionId) { return -EINVAL; } - return mPlugin->closeSession(sessionId); + status_t err = mPlugin->closeSession(sessionId); + if (err == OK) { + DrmSessionManager::Instance()->removeSession(sessionId); + } + return err; } status_t Drm::getKeyRequest(Vector const &sessionId, @@ -321,6 +369,8 @@ status_t Drm::getKeyRequest(Vector const &sessionId, return -EINVAL; } + DrmSessionManager::Instance()->useSession(sessionId); + return mPlugin->getKeyRequest(sessionId, initData, mimeType, keyType, optionalParameters, request, defaultUrl); } @@ -338,6 +388,8 @@ status_t Drm::provideKeyResponse(Vector const &sessionId, return -EINVAL; } + DrmSessionManager::Instance()->useSession(sessionId); + return mPlugin->provideKeyResponse(sessionId, response, keySetId); } @@ -367,6 +419,8 @@ status_t Drm::restoreKeys(Vector const &sessionId, return -EINVAL; } + DrmSessionManager::Instance()->useSession(sessionId); + return mPlugin->restoreKeys(sessionId, keySetId); } @@ -382,6 +436,8 @@ status_t Drm::queryKeyStatus(Vector const &sessionId, return -EINVAL; } + DrmSessionManager::Instance()->useSession(sessionId); + return mPlugin->queryKeyStatus(sessionId, infoMap); } @@ -561,6 +617,8 @@ status_t Drm::setCipherAlgorithm(Vector const &sessionId, return -EINVAL; } + DrmSessionManager::Instance()->useSession(sessionId); + return mPlugin->setCipherAlgorithm(sessionId, algorithm); } @@ -576,6 +634,8 @@ status_t Drm::setMacAlgorithm(Vector const &sessionId, return -EINVAL; } + DrmSessionManager::Instance()->useSession(sessionId); + return mPlugin->setMacAlgorithm(sessionId, algorithm); } @@ -594,6 +654,8 @@ status_t Drm::encrypt(Vector const &sessionId, return -EINVAL; } + DrmSessionManager::Instance()->useSession(sessionId); + return mPlugin->encrypt(sessionId, keyId, input, iv, output); } @@ -612,6 +674,8 @@ status_t Drm::decrypt(Vector const &sessionId, return -EINVAL; } + DrmSessionManager::Instance()->useSession(sessionId); + return mPlugin->decrypt(sessionId, keyId, input, iv, output); } @@ -629,6 +693,8 @@ status_t Drm::sign(Vector const &sessionId, return -EINVAL; } + DrmSessionManager::Instance()->useSession(sessionId); + return mPlugin->sign(sessionId, keyId, message, signature); } @@ -647,6 +713,8 @@ status_t Drm::verify(Vector const &sessionId, return -EINVAL; } + DrmSessionManager::Instance()->useSession(sessionId); + return mPlugin->verify(sessionId, keyId, message, signature, match); } @@ -669,6 +737,8 @@ status_t Drm::signRSA(Vector const &sessionId, return -EPERM; } + DrmSessionManager::Instance()->useSession(sessionId); + return mPlugin->signRSA(sessionId, algorithm, message, wrappedKey, signature); } diff --git a/media/libmediaplayerservice/Drm.h b/media/libmediaplayerservice/Drm.h index 0e1eb2c..0cea639 100644 --- a/media/libmediaplayerservice/Drm.h +++ b/media/libmediaplayerservice/Drm.h @@ -28,6 +28,7 @@ namespace android { struct DrmFactory; struct DrmPlugin; +struct DrmSessionClientInterface; struct Drm : public BnDrm, public IBinder::DeathRecipient, @@ -138,6 +139,8 @@ private: status_t mInitCheck; + sp mDrmSessionClient; + sp mListener; mutable Mutex mEventLock; mutable Mutex mNotifyLock; diff --git a/media/libmediaplayerservice/DrmSessionManager.cpp b/media/libmediaplayerservice/DrmSessionManager.cpp index 43346e0..6e17eb1 100644 --- a/media/libmediaplayerservice/DrmSessionManager.cpp +++ b/media/libmediaplayerservice/DrmSessionManager.cpp @@ -23,6 +23,8 @@ #include "DrmSessionClientInterface.h" #include "ProcessInfoInterface.h" #include +#include +#include #include #include @@ -39,12 +41,25 @@ static String8 GetSessionIdString(const Vector &sessionId) { struct ProcessInfo : public ProcessInfoInterface { ProcessInfo() {} - virtual int getPriority(int pid) { - // TODO: implement - // Get process state to determine priority. - // According to the define of PROCESS_STATE_***, higher the value lower - // the priority. So we will do a converting from state to priority here. - return -1; + virtual bool getPriority(int pid, int* priority) { + sp binder = defaultServiceManager()->getService(String16("processinfo")); + sp service = interface_cast(binder); + + size_t length = 1; + int32_t states; + status_t err = service->getProcessStatesFromPids(length, &pid, &states); + if (err != OK) { + ALOGE("getProcessStatesFromPids failed"); + return false; + } + ALOGV("pid %d states %d", pid, states); + if (states < 0) { + return false; + } + + // Use process state as the priority. Lower the value, higher the priority. + *priority = states; + return true; } protected: @@ -66,6 +81,11 @@ bool isEqualSessionId(const Vector &sessionId1, const Vector & return true; } +sp DrmSessionManager::Instance() { + static sp drmSessionManager = new DrmSessionManager(); + return drmSessionManager; +} + DrmSessionManager::DrmSessionManager() : mProcessInfo(new ProcessInfo()), mTime(0) {} @@ -155,15 +175,18 @@ bool DrmSessionManager::reclaimSession(int callingPid) { sp drm; Vector sessionId; + int lowestPriorityPid; + int lowestPriority; { Mutex::Autolock lock(mLock); - int callingPriority = mProcessInfo->getPriority(callingPid); - int lowestPriorityPid; - int lowestPriority; + int callingPriority; + if (!mProcessInfo->getPriority(callingPid, &callingPriority)) { + return false; + } if (!getLowestPriority_l(&lowestPriorityPid, &lowestPriority)) { return false; } - if (lowestPriority >= callingPriority) { + if (lowestPriority <= callingPriority) { return false; } @@ -176,6 +199,9 @@ bool DrmSessionManager::reclaimSession(int callingPid) { return false; } + ALOGV("reclaim session(%s) opened by pid %d", + GetSessionIdString(sessionId).string(), lowestPriorityPid); + return drm->reclaimSession(sessionId); } @@ -185,19 +211,23 @@ int64_t DrmSessionManager::getTime_l() { bool DrmSessionManager::getLowestPriority_l(int* lowestPriorityPid, int* lowestPriority) { int pid = -1; - int priority = INT_MAX; + int priority = -1; for (size_t i = 0; i < mSessionMap.size(); ++i) { if (mSessionMap.valueAt(i).size() == 0) { // no opened session by this process. continue; } int tempPid = mSessionMap.keyAt(i); - int tempPriority = mProcessInfo->getPriority(tempPid); + int tempPriority; + if (!mProcessInfo->getPriority(tempPid, &tempPriority)) { + // shouldn't happen. + return false; + } if (pid == -1) { pid = tempPid; priority = tempPriority; } else { - if (tempPriority < priority) { + if (tempPriority > priority) { pid = tempPid; priority = tempPriority; } diff --git a/media/libmediaplayerservice/DrmSessionManager.h b/media/libmediaplayerservice/DrmSessionManager.h index 1d0ed43..ba5c268 100644 --- a/media/libmediaplayerservice/DrmSessionManager.h +++ b/media/libmediaplayerservice/DrmSessionManager.h @@ -42,6 +42,8 @@ typedef Vector SessionInfos; typedef KeyedVector PidSessionInfosMap; struct DrmSessionManager : public RefBase { + static sp Instance(); + DrmSessionManager(); DrmSessionManager(sp processInfo); diff --git a/media/libmediaplayerservice/ProcessInfoInterface.h b/media/libmediaplayerservice/ProcessInfoInterface.h index bdcc1da..222f92d 100644 --- a/media/libmediaplayerservice/ProcessInfoInterface.h +++ b/media/libmediaplayerservice/ProcessInfoInterface.h @@ -22,7 +22,7 @@ namespace android { struct ProcessInfoInterface : public RefBase { - virtual int getPriority(int pid) = 0; + virtual bool getPriority(int pid, int* priority) = 0; protected: virtual ~ProcessInfoInterface() {} diff --git a/media/libmediaplayerservice/tests/DrmSessionManager_test.cpp b/media/libmediaplayerservice/tests/DrmSessionManager_test.cpp index a199ee1..782c1a5 100644 --- a/media/libmediaplayerservice/tests/DrmSessionManager_test.cpp +++ b/media/libmediaplayerservice/tests/DrmSessionManager_test.cpp @@ -32,7 +32,12 @@ struct FakeProcessInfo : public ProcessInfoInterface { FakeProcessInfo() {} virtual ~FakeProcessInfo() {} - virtual int getPriority(int pid) { return pid; } + virtual bool getPriority(int pid, int* priority) { + // For testing, use pid as priority. + // Lower the value higher the priority. + *priority = pid; + return true; + } private: DISALLOW_EVIL_CONSTRUCTORS(FakeProcessInfo); @@ -57,7 +62,7 @@ private: DISALLOW_EVIL_CONSTRUCTORS(FakeDrm); }; -static const int kTestPid1 = 10; +static const int kTestPid1 = 30; static const int kTestPid2 = 20; static const uint8_t kTestSessionId1[] = {1, 2, 3}; static const uint8_t kTestSessionId2[] = {4, 5, 6, 7, 8}; @@ -122,7 +127,9 @@ protected: EXPECT_EQ(kTestPid1, pid); FakeProcessInfo processInfo; - EXPECT_EQ(processInfo.getPriority(kTestPid1), priority); + int priority1; + processInfo.getPriority(kTestPid1, &priority1); + EXPECT_EQ(priority1, priority); } void testGetLeastUsedSession() { @@ -210,9 +217,9 @@ TEST_F(DrmSessionManagerTest, reclaimSession) { addSession(); // calling pid priority is too low - EXPECT_FALSE(mDrmSessionManager->reclaimSession(5)); + EXPECT_FALSE(mDrmSessionManager->reclaimSession(50)); - EXPECT_TRUE(mDrmSessionManager->reclaimSession(30)); + EXPECT_TRUE(mDrmSessionManager->reclaimSession(10)); EXPECT_EQ(1, mTestDrm1->reclaimedSessions().size()); EXPECT_TRUE(isEqualSessionId(mSessionId1, mTestDrm1->reclaimedSessions()[0])); @@ -223,9 +230,9 @@ TEST_F(DrmSessionManagerTest, reclaimSession) { const uint8_t ids[] = {456, 7890, 123}; Vector sessionId; GetSessionId(ids, ARRAY_SIZE(ids), &sessionId); - mDrmSessionManager->addSession(30, drm, sessionId); + mDrmSessionManager->addSession(15, drm, sessionId); - EXPECT_TRUE(mDrmSessionManager->reclaimSession(40)); + EXPECT_TRUE(mDrmSessionManager->reclaimSession(18)); EXPECT_EQ(1, mTestDrm2->reclaimedSessions().size()); // mSessionId2 is reclaimed. EXPECT_TRUE(isEqualSessionId(mSessionId2, mTestDrm2->reclaimedSessions()[0])); -- cgit v1.1