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