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 <aidl/android/media/IResourceManagerClient.h>
22 #include <aidl/android/media/IResourceManagerService.h>
23 #include <aidl/android/media/MediaResourceParcel.h>
24 #include <android/binder_ibinder.h>
25 #include <android/binder_manager.h>
26 #include <cutils/properties.h>
27 #include <mediadrm/DrmUtils.h>
28 #include <mediadrm/DrmSessionManager.h>
29 #include <unistd.h>
30 #include <utils/String8.h>
31
32 #include <vector>
33
34 namespace android {
35
36 using aidl::android::media::MediaResourceParcel;
37
38 namespace {
ResourceManagerServiceDied(void * cookie)39 void ResourceManagerServiceDied(void* cookie) {
40 auto thiz = static_cast<DrmSessionManager*>(cookie);
41 thiz->binderDied();
42 }
43 }
44
45 using ::ndk::ScopedAStatus;
46
GetSessionIdString(const Vector<uint8_t> & sessionId)47 static String8 GetSessionIdString(const Vector<uint8_t> &sessionId) {
48 String8 sessionIdStr;
49 for (size_t i = 0; i < sessionId.size(); ++i) {
50 sessionIdStr.appendFormat("%u ", sessionId[i]);
51 }
52 return sessionIdStr;
53 }
54
55 template <typename Byte = uint8_t>
toStdVec(const Vector<uint8_t> & vector)56 static std::vector<Byte> toStdVec(const Vector<uint8_t> &vector) {
57 auto v = reinterpret_cast<const Byte *>(vector.array());
58 std::vector<Byte> vec(v, v + vector.size());
59 return vec;
60 }
61
toResourceVec(const Vector<uint8_t> & sessionId,int64_t value)62 static std::vector<MediaResourceParcel> toResourceVec(
63 const Vector<uint8_t> &sessionId, int64_t value) {
64 using Type = aidl::android::media::MediaResourceType;
65 using SubType = aidl::android::media::MediaResourceSubType;
66 std::vector<MediaResourceParcel> resources;
67 MediaResourceParcel resource{
68 Type::kDrmSession, SubType::kUnspecifiedSubType,
69 toStdVec<>(sessionId), value};
70 resources.push_back(resource);
71 return resources;
72 }
73
getResourceManagerService()74 static std::shared_ptr<IResourceManagerService> getResourceManagerService() {
75 ::ndk::SpAIBinder binder(AServiceManager_getService("media.resource_manager"));
76 return IResourceManagerService::fromBinder(binder);
77 }
78
isEqualSessionId(const Vector<uint8_t> & sessionId1,const Vector<uint8_t> & sessionId2)79 bool isEqualSessionId(const Vector<uint8_t> &sessionId1, const Vector<uint8_t> &sessionId2) {
80 if (sessionId1.size() != sessionId2.size()) {
81 return false;
82 }
83 for (size_t i = 0; i < sessionId1.size(); ++i) {
84 if (sessionId1[i] != sessionId2[i]) {
85 return false;
86 }
87 }
88 return true;
89 }
90
Instance()91 sp<DrmSessionManager> DrmSessionManager::Instance() {
92 static sp<DrmSessionManager> drmSessionManager = new DrmSessionManager();
93 drmSessionManager->init();
94 return drmSessionManager;
95 }
96
DrmSessionManager()97 DrmSessionManager::DrmSessionManager()
98 : DrmSessionManager(getResourceManagerService()) {
99 }
100
DrmSessionManager(const std::shared_ptr<IResourceManagerService> & service)101 DrmSessionManager::DrmSessionManager(const std::shared_ptr<IResourceManagerService> &service)
102 : mService(service),
103 mInitialized(false),
104 mDeathRecipient(AIBinder_DeathRecipient_new(ResourceManagerServiceDied)) {
105 if (mService == NULL) {
106 ALOGE("Failed to init ResourceManagerService");
107 }
108 }
109
~DrmSessionManager()110 DrmSessionManager::~DrmSessionManager() {
111 if (mService != NULL) {
112 AIBinder_unlinkToDeath(mService->asBinder().get(), mDeathRecipient.get(), this);
113 }
114 }
115
init()116 void DrmSessionManager::init() {
117 Mutex::Autolock lock(mLock);
118 if (mInitialized) {
119 return;
120 }
121 mInitialized = true;
122 if (mService != NULL) {
123 AIBinder_linkToDeath(mService->asBinder().get(), mDeathRecipient.get(), this);
124 }
125 }
126
addSession(int pid,const std::shared_ptr<IResourceManagerClient> & drm,const Vector<uint8_t> & sessionId)127 void DrmSessionManager::addSession(int pid,
128 const std::shared_ptr<IResourceManagerClient>& drm, const Vector<uint8_t> &sessionId) {
129 uid_t uid = AIBinder_getCallingUid();
130 ALOGV("addSession(pid %d, uid %d, drm %p, sessionId %s)", pid, uid, drm.get(),
131 GetSessionIdString(sessionId).string());
132
133 Mutex::Autolock lock(mLock);
134 if (mService == NULL) {
135 return;
136 }
137
138 static int64_t clientId = 0;
139 mSessionMap[toStdVec(sessionId)] = (SessionInfo){pid, uid, clientId};
140 mService->addResource(pid, uid, clientId++, drm, toResourceVec(sessionId, INT64_MAX));
141 }
142
useSession(const Vector<uint8_t> & sessionId)143 void DrmSessionManager::useSession(const Vector<uint8_t> &sessionId) {
144 ALOGV("useSession(%s)", GetSessionIdString(sessionId).string());
145
146 Mutex::Autolock lock(mLock);
147 auto it = mSessionMap.find(toStdVec(sessionId));
148 if (mService == NULL || it == mSessionMap.end()) {
149 return;
150 }
151
152 auto info = it->second;
153 mService->addResource(info.pid, info.uid, info.clientId, NULL, toResourceVec(sessionId, -1));
154 }
155
removeSession(const Vector<uint8_t> & sessionId)156 void DrmSessionManager::removeSession(const Vector<uint8_t> &sessionId) {
157 ALOGV("removeSession(%s)", GetSessionIdString(sessionId).string());
158
159 Mutex::Autolock lock(mLock);
160 auto it = mSessionMap.find(toStdVec(sessionId));
161 if (mService == NULL || it == mSessionMap.end()) {
162 return;
163 }
164
165 auto info = it->second;
166 // removeClient instead of removeSession because each client has only one session
167 mService->removeClient(info.pid, info.clientId);
168 mSessionMap.erase(it);
169 }
170
reclaimSession(int callingPid)171 bool DrmSessionManager::reclaimSession(int callingPid) {
172 ALOGV("reclaimSession(%d)", callingPid);
173
174 // unlock early because reclaimResource might callback into removeSession
175 mLock.lock();
176 std::shared_ptr<IResourceManagerService> service(mService);
177 mLock.unlock();
178
179 if (service == NULL) {
180 return false;
181 }
182
183 // cannot update mSessionMap because we do not know which sessionId is reclaimed;
184 // we rely on IResourceManagerClient to removeSession in reclaimResource
185 Vector<uint8_t> dummy;
186 bool success;
187 ScopedAStatus status = service->reclaimResource(callingPid, toResourceVec(dummy, INT64_MAX), &success);
188 return status.isOk() && success;
189 }
190
getSessionCount() const191 size_t DrmSessionManager::getSessionCount() const {
192 Mutex::Autolock lock(mLock);
193 return mSessionMap.size();
194 }
195
containsSession(const Vector<uint8_t> & sessionId) const196 bool DrmSessionManager::containsSession(const Vector<uint8_t>& sessionId) const {
197 Mutex::Autolock lock(mLock);
198 return mSessionMap.count(toStdVec(sessionId));
199 }
200
binderDied()201 void DrmSessionManager::binderDied() {
202 ALOGW("ResourceManagerService died.");
203 Mutex::Autolock lock(mLock);
204 mService.reset();
205 }
206
207 } // namespace android
208