/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ //#define LOG_NDEBUG 0 #define LOG_TAG "DrmSessionManager" #include #include #include #include #include #include #include #include #include #include #include #include namespace android { using aidl::android::media::MediaResourceParcel; namespace { void ResourceManagerServiceDied(void* cookie) { auto thiz = static_cast(cookie); thiz->binderDied(); } } using ::ndk::ScopedAStatus; static String8 GetSessionIdString(const Vector &sessionId) { String8 sessionIdStr; for (size_t i = 0; i < sessionId.size(); ++i) { sessionIdStr.appendFormat("%u ", sessionId[i]); } return sessionIdStr; } template static std::vector toStdVec(const Vector &vector) { auto v = reinterpret_cast(vector.array()); std::vector vec(v, v + vector.size()); return vec; } static std::vector toResourceVec( const Vector &sessionId, int64_t value) { using Type = aidl::android::media::MediaResourceType; using SubType = aidl::android::media::MediaResourceSubType; std::vector resources; MediaResourceParcel resource{ Type::kDrmSession, SubType::kUnspecifiedSubType, toStdVec(sessionId), value}; resources.push_back(resource); return resources; } static std::shared_ptr getResourceManagerService() { ::ndk::SpAIBinder binder(AServiceManager_getService("media.resource_manager")); return IResourceManagerService::fromBinder(binder); } bool isEqualSessionId(const Vector &sessionId1, const Vector &sessionId2) { if (sessionId1.size() != sessionId2.size()) { return false; } for (size_t i = 0; i < sessionId1.size(); ++i) { if (sessionId1[i] != sessionId2[i]) { return false; } } return true; } sp DrmSessionManager::Instance() { static sp drmSessionManager = new DrmSessionManager(); drmSessionManager->init(); return drmSessionManager; } DrmSessionManager::DrmSessionManager() : DrmSessionManager(getResourceManagerService()) { } DrmSessionManager::DrmSessionManager(const std::shared_ptr &service) : mService(service), mInitialized(false), mDeathRecipient(AIBinder_DeathRecipient_new(ResourceManagerServiceDied)) { if (mService == NULL) { ALOGE("Failed to init ResourceManagerService"); } } DrmSessionManager::~DrmSessionManager() { if (mService != NULL) { AIBinder_unlinkToDeath(mService->asBinder().get(), mDeathRecipient.get(), this); } } void DrmSessionManager::init() { Mutex::Autolock lock(mLock); if (mInitialized) { return; } mInitialized = true; if (mService != NULL) { AIBinder_linkToDeath(mService->asBinder().get(), mDeathRecipient.get(), this); } } void DrmSessionManager::addSession(int pid, const std::shared_ptr& drm, const Vector &sessionId) { uid_t uid = AIBinder_getCallingUid(); ALOGV("addSession(pid %d, uid %d, drm %p, sessionId %s)", pid, uid, drm.get(), GetSessionIdString(sessionId).string()); Mutex::Autolock lock(mLock); if (mService == NULL) { return; } static int64_t clientId = 0; mSessionMap[toStdVec(sessionId)] = (SessionInfo){pid, uid, clientId}; mService->addResource(pid, uid, clientId++, drm, toResourceVec(sessionId, INT64_MAX)); } void DrmSessionManager::useSession(const Vector &sessionId) { ALOGV("useSession(%s)", GetSessionIdString(sessionId).string()); Mutex::Autolock lock(mLock); auto it = mSessionMap.find(toStdVec(sessionId)); if (mService == NULL || it == mSessionMap.end()) { return; } auto info = it->second; mService->addResource(info.pid, info.uid, info.clientId, NULL, toResourceVec(sessionId, -1)); } void DrmSessionManager::removeSession(const Vector &sessionId) { ALOGV("removeSession(%s)", GetSessionIdString(sessionId).string()); Mutex::Autolock lock(mLock); auto it = mSessionMap.find(toStdVec(sessionId)); if (mService == NULL || it == mSessionMap.end()) { return; } auto info = it->second; // removeClient instead of removeSession because each client has only one session mService->removeClient(info.pid, info.clientId); mSessionMap.erase(it); } bool DrmSessionManager::reclaimSession(int callingPid) { ALOGV("reclaimSession(%d)", callingPid); // unlock early because reclaimResource might callback into removeSession mLock.lock(); std::shared_ptr service(mService); mLock.unlock(); if (service == NULL) { return false; } // cannot update mSessionMap because we do not know which sessionId is reclaimed; // we rely on IResourceManagerClient to removeSession in reclaimResource Vector dummy; bool success; ScopedAStatus status = service->reclaimResource(callingPid, toResourceVec(dummy, INT64_MAX), &success); return status.isOk() && success; } size_t DrmSessionManager::getSessionCount() const { Mutex::Autolock lock(mLock); return mSessionMap.size(); } bool DrmSessionManager::containsSession(const Vector& sessionId) const { Mutex::Autolock lock(mLock); return mSessionMap.count(toStdVec(sessionId)); } void DrmSessionManager::binderDied() { ALOGW("ResourceManagerService died."); Mutex::Autolock lock(mLock); mService.reset(); } } // namespace android