1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 //#define LOG_NDEBUG 0
18 #define LOG_TAG "DrmSessionManager"
19 #include <utils/Log.h>
20 
21 #include <binder/IPCThreadState.h>
22 #include <binder/IProcessInfoService.h>
23 #include <binder/IServiceManager.h>
24 #include <cutils/properties.h>
25 #include <media/IResourceManagerClient.h>
26 #include <media/MediaResource.h>
27 #include <mediadrm/DrmSessionManager.h>
28 #include <unistd.h>
29 #include <utils/String8.h>
30 
31 #include <vector>
32 
33 #include "ResourceManagerService.h"
34 
35 namespace android {
36 
GetSessionIdString(const Vector<uint8_t> & sessionId)37 static String8 GetSessionIdString(const Vector<uint8_t> &sessionId) {
38     String8 sessionIdStr;
39     for (size_t i = 0; i < sessionId.size(); ++i) {
40         sessionIdStr.appendFormat("%u ", sessionId[i]);
41     }
42     return sessionIdStr;
43 }
44 
toStdVec(const Vector<uint8_t> & vector)45 static std::vector<uint8_t> toStdVec(const Vector<uint8_t> &vector) {
46     const uint8_t *v = vector.array();
47     std::vector<uint8_t> vec(v, v + vector.size());
48     return vec;
49 }
50 
toClientId(const sp<IResourceManagerClient> & drm)51 static uint64_t toClientId(const sp<IResourceManagerClient>& drm) {
52     return reinterpret_cast<int64_t>(drm.get());
53 }
54 
toResourceVec(const Vector<uint8_t> & sessionId)55 static Vector<MediaResource> toResourceVec(const Vector<uint8_t> &sessionId) {
56     Vector<MediaResource> resources;
57     // use UINT64_MAX to decrement through addition overflow
58     resources.push_back(MediaResource(MediaResource::kDrmSession, toStdVec(sessionId), UINT64_MAX));
59     return resources;
60 }
61 
getResourceManagerService()62 static sp<IResourceManagerService> getResourceManagerService() {
63     if (property_get_bool("persist.device_config.media_native.mediadrmserver", 1)) {
64         return new ResourceManagerService();
65     }
66     sp<IServiceManager> sm = defaultServiceManager();
67     if (sm == NULL) {
68         return NULL;
69     }
70     sp<IBinder> binder = sm->getService(String16("media.resource_manager"));
71     return interface_cast<IResourceManagerService>(binder);
72 }
73 
isEqualSessionId(const Vector<uint8_t> & sessionId1,const Vector<uint8_t> & sessionId2)74 bool isEqualSessionId(const Vector<uint8_t> &sessionId1, const Vector<uint8_t> &sessionId2) {
75     if (sessionId1.size() != sessionId2.size()) {
76         return false;
77     }
78     for (size_t i = 0; i < sessionId1.size(); ++i) {
79         if (sessionId1[i] != sessionId2[i]) {
80             return false;
81         }
82     }
83     return true;
84 }
85 
Instance()86 sp<DrmSessionManager> DrmSessionManager::Instance() {
87     static sp<DrmSessionManager> drmSessionManager = new DrmSessionManager();
88     drmSessionManager->init();
89     return drmSessionManager;
90 }
91 
DrmSessionManager()92 DrmSessionManager::DrmSessionManager()
93     : DrmSessionManager(getResourceManagerService()) {
94 }
95 
DrmSessionManager(const sp<IResourceManagerService> & service)96 DrmSessionManager::DrmSessionManager(const sp<IResourceManagerService> &service)
97     : mService(service),
98       mInitialized(false) {
99     if (mService == NULL) {
100         ALOGE("Failed to init ResourceManagerService");
101     }
102 }
103 
~DrmSessionManager()104 DrmSessionManager::~DrmSessionManager() {
105     if (mService != NULL) {
106         IInterface::asBinder(mService)->unlinkToDeath(this);
107     }
108 }
109 
init()110 void DrmSessionManager::init() {
111     Mutex::Autolock lock(mLock);
112     if (mInitialized) {
113         return;
114     }
115     mInitialized = true;
116     if (mService != NULL) {
117         IInterface::asBinder(mService)->linkToDeath(this);
118     }
119 }
120 
addSession(int pid,const sp<IResourceManagerClient> & drm,const Vector<uint8_t> & sessionId)121 void DrmSessionManager::addSession(int pid,
122         const sp<IResourceManagerClient>& drm, const Vector<uint8_t> &sessionId) {
123     uid_t uid = IPCThreadState::self()->getCallingUid();
124     ALOGV("addSession(pid %d, uid %d, drm %p, sessionId %s)", pid, uid, drm.get(),
125             GetSessionIdString(sessionId).string());
126 
127     Mutex::Autolock lock(mLock);
128     if (mService == NULL) {
129         return;
130     }
131 
132     int64_t clientId = toClientId(drm);
133     mSessionMap[toStdVec(sessionId)] = (SessionInfo){pid, uid, clientId};
134     mService->addResource(pid, uid, clientId, drm, toResourceVec(sessionId));
135 }
136 
useSession(const Vector<uint8_t> & sessionId)137 void DrmSessionManager::useSession(const Vector<uint8_t> &sessionId) {
138     ALOGV("useSession(%s)", GetSessionIdString(sessionId).string());
139 
140     Mutex::Autolock lock(mLock);
141     auto it = mSessionMap.find(toStdVec(sessionId));
142     if (mService == NULL || it == mSessionMap.end()) {
143         return;
144     }
145 
146     auto info = it->second;
147     mService->addResource(info.pid, info.uid, info.clientId, NULL, toResourceVec(sessionId));
148 }
149 
removeSession(const Vector<uint8_t> & sessionId)150 void DrmSessionManager::removeSession(const Vector<uint8_t> &sessionId) {
151     ALOGV("removeSession(%s)", GetSessionIdString(sessionId).string());
152 
153     Mutex::Autolock lock(mLock);
154     auto it = mSessionMap.find(toStdVec(sessionId));
155     if (mService == NULL || it == mSessionMap.end()) {
156         return;
157     }
158 
159     auto info = it->second;
160     mService->removeResource(info.pid, info.clientId, toResourceVec(sessionId));
161     mSessionMap.erase(it);
162 }
163 
reclaimSession(int callingPid)164 bool DrmSessionManager::reclaimSession(int callingPid) {
165     ALOGV("reclaimSession(%d)", callingPid);
166 
167     // unlock early because reclaimResource might callback into removeSession
168     mLock.lock();
169     sp<IResourceManagerService> service(mService);
170     mLock.unlock();
171 
172     if (service == NULL) {
173         return false;
174     }
175 
176     // cannot update mSessionMap because we do not know which sessionId is reclaimed;
177     // we rely on IResourceManagerClient to removeSession in reclaimResource
178     Vector<uint8_t> dummy;
179     return service->reclaimResource(callingPid, toResourceVec(dummy));
180 }
181 
getSessionCount() const182 size_t DrmSessionManager::getSessionCount() const {
183     Mutex::Autolock lock(mLock);
184     return mSessionMap.size();
185 }
186 
containsSession(const Vector<uint8_t> & sessionId) const187 bool DrmSessionManager::containsSession(const Vector<uint8_t>& sessionId) const {
188     Mutex::Autolock lock(mLock);
189     return mSessionMap.count(toStdVec(sessionId));
190 }
191 
binderDied(const wp<IBinder> &)192 void DrmSessionManager::binderDied(const wp<IBinder>& /*who*/) {
193     ALOGW("ResourceManagerService died.");
194     Mutex::Autolock lock(mLock);
195     mService.clear();
196 }
197 
198 }  // namespace android
199