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