blob: 989a5974f3709f2145a327aabdd15cbcf8d3699e [file] [log] [blame]
Ronghua Wu10305cc2015-02-22 07:55:32 -08001/*
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
Robert Shih0f3a8a02019-11-14 15:43:39 -080021#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>
Robert Shihc3af31b2019-09-20 21:45:01 -070026#include <cutils/properties.h>
Robert Shih28c2ed32019-10-27 22:55:12 -070027#include <mediadrm/DrmUtils.h>
Jeff Tinker7d2c6e82018-02-16 16:14:59 -080028#include <mediadrm/DrmSessionManager.h>
Ronghua Wu10305cc2015-02-22 07:55:32 -080029#include <unistd.h>
30#include <utils/String8.h>
31
Robert Shihc3af31b2019-09-20 21:45:01 -070032#include <vector>
33
Ronghua Wu10305cc2015-02-22 07:55:32 -080034namespace android {
Robert Shih0f3a8a02019-11-14 15:43:39 -080035
36using aidl::android::media::MediaResourceParcel;
Girish9128e242022-11-23 20:52:29 +000037using aidl::android::media::ClientInfoParcel;
Robert Shih0f3a8a02019-11-14 15:43:39 -080038
Robert Shih0f3a8a02019-11-14 15:43:39 -080039using ::ndk::ScopedAStatus;
Ronghua Wu10305cc2015-02-22 07:55:32 -080040
41static String8 GetSessionIdString(const Vector<uint8_t> &sessionId) {
42 String8 sessionIdStr;
43 for (size_t i = 0; i < sessionId.size(); ++i) {
44 sessionIdStr.appendFormat("%u ", sessionId[i]);
45 }
46 return sessionIdStr;
47}
48
Robert Shih0f3a8a02019-11-14 15:43:39 -080049template <typename Byte = uint8_t>
50static std::vector<Byte> toStdVec(const Vector<uint8_t> &vector) {
51 auto v = reinterpret_cast<const Byte *>(vector.array());
52 std::vector<Byte> vec(v, v + vector.size());
Robert Shihc3af31b2019-09-20 21:45:01 -070053 return vec;
54}
55
Girish323711f2023-05-24 21:47:34 +000056static Vector<uint8_t> toAndroidVec(const std::vector<uint8_t>& array) {
57 Vector<uint8_t> vec;
58 vec.appendArray(array.data(), array.size());
59 return vec;
60}
61
Chong Zhang181e6952019-10-09 13:23:39 -070062static std::vector<MediaResourceParcel> toResourceVec(
63 const Vector<uint8_t> &sessionId, int64_t value) {
Robert Shih0f3a8a02019-11-14 15:43:39 -080064 using Type = aidl::android::media::MediaResourceType;
65 using SubType = aidl::android::media::MediaResourceSubType;
Chong Zhang181e6952019-10-09 13:23:39 -070066 std::vector<MediaResourceParcel> resources;
Robert Shih0f3a8a02019-11-14 15:43:39 -080067 MediaResourceParcel resource{
68 Type::kDrmSession, SubType::kUnspecifiedSubType,
Jooyung Han3d564ff2020-02-22 00:46:06 +090069 toStdVec<>(sessionId), value};
Robert Shih0f3a8a02019-11-14 15:43:39 -080070 resources.push_back(resource);
Robert Shihc3af31b2019-09-20 21:45:01 -070071 return resources;
72}
73
Ronghua Wu10305cc2015-02-22 07:55:32 -080074bool 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
Ronghua Wu5c3da202015-02-22 08:45:28 -080086sp<DrmSessionManager> DrmSessionManager::Instance() {
Robert Shihfc62baf2020-03-13 21:49:06 -070087 static sp<DrmSessionManager> drmSessionManager = new DrmSessionManager();
Robert Shihc3af31b2019-09-20 21:45:01 -070088 drmSessionManager->init();
Ronghua Wu5c3da202015-02-22 08:45:28 -080089 return drmSessionManager;
90}
91
Ronghua Wu10305cc2015-02-22 07:55:32 -080092DrmSessionManager::DrmSessionManager()
Girish323711f2023-05-24 21:47:34 +000093 : DrmSessionManager(nullptr) {
Robert Shihc3af31b2019-09-20 21:45:01 -070094}
Ronghua Wu10305cc2015-02-22 07:55:32 -080095
Robert Shih0f3a8a02019-11-14 15:43:39 -080096DrmSessionManager::DrmSessionManager(const std::shared_ptr<IResourceManagerService> &service)
Robert Shihc3af31b2019-09-20 21:45:01 -070097 : mService(service),
Girish323711f2023-05-24 21:47:34 +000098 mDeathRecipient(::ndk::ScopedAIBinder_DeathRecipient(
99 AIBinder_DeathRecipient_new(ResourceManagerServiceDied))) {
100 // Setting callback notification when DeathRecipient gets deleted.
101 AIBinder_DeathRecipient_setOnUnlinked(mDeathRecipient.get(), BinderUnlinkedCallback);
Robert Shihc3af31b2019-09-20 21:45:01 -0700102}
Ronghua Wu10305cc2015-02-22 07:55:32 -0800103
Robert Shihc3af31b2019-09-20 21:45:01 -0700104DrmSessionManager::~DrmSessionManager() {
105 if (mService != NULL) {
Robert Shih0f3a8a02019-11-14 15:43:39 -0800106 AIBinder_unlinkToDeath(mService->asBinder().get(), mDeathRecipient.get(), this);
Robert Shihc3af31b2019-09-20 21:45:01 -0700107 }
108}
Ronghua Wu10305cc2015-02-22 07:55:32 -0800109
Girish323711f2023-05-24 21:47:34 +0000110status_t DrmSessionManager::init() {
Robert Shihc3af31b2019-09-20 21:45:01 -0700111 Mutex::Autolock lock(mLock);
Girish323711f2023-05-24 21:47:34 +0000112 getResourceManagerService_l();
113 if (mService == nullptr) {
114 ALOGE("Failed to init ResourceManagerService");
115 return DEAD_OBJECT;
116 }
117
118 return OK;
119}
120
121void DrmSessionManager::getResourceManagerService_l() {
122 if (mService != nullptr) {
Robert Shihc3af31b2019-09-20 21:45:01 -0700123 return;
124 }
Girish323711f2023-05-24 21:47:34 +0000125
126 // Get binder interface to resource manager.
127 ::ndk::SpAIBinder binder(AServiceManager_waitForService("media.resource_manager"));
128 mService = IResourceManagerService::fromBinder(binder);
129 if (mService == nullptr) {
130 ALOGE("Failed to get ResourceManagerService");
131 return;
132 }
133
134 // Create the context that is passed as cookie to the binder death notification.
135 // The context gets deleted at BinderUnlinkedCallback.
136 BinderDiedContext* context = new BinderDiedContext{
137 .mDrmSessionManager = wp<DrmSessionManager>::fromExisting(this)};
138 // Register for the callbacks by linking to death notification.
139 AIBinder_linkToDeath(mService->asBinder().get(), mDeathRecipient.get(), context);
140
141 // If the RM was restarted, re-register all the resources.
142 if (mBinderDied) {
143 reRegisterAllResources_l();
144 mBinderDied = false;
145 }
146}
147
148void DrmSessionManager::reRegisterAllResources_l() {
149 if (mSessionMap.empty()) {
150 // Nothing to register.
151 ALOGV("No resources to add");
152 return;
153 }
154
155 if (mService == nullptr) {
156 ALOGW("Service isn't available");
157 return;
158 }
159
160 // Go through the session map and re-register all the resources for those sessions.
161 for (SessionInfoMap::const_iterator iter = mSessionMap.begin();
162 iter != mSessionMap.end(); ++iter) {
163 ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(iter->second.pid),
164 .uid = static_cast<int32_t>(iter->second.uid),
165 .id = iter->second.clientId};
166 mService->addResource(clientInfo, iter->second.drm,
167 toResourceVec(toAndroidVec(iter->first), iter->second.resourceValue));
Robert Shihc3af31b2019-09-20 21:45:01 -0700168 }
169}
170
171void DrmSessionManager::addSession(int pid,
Robert Shih0f3a8a02019-11-14 15:43:39 -0800172 const std::shared_ptr<IResourceManagerClient>& drm, const Vector<uint8_t> &sessionId) {
173 uid_t uid = AIBinder_getCallingUid();
Robert Shihc3af31b2019-09-20 21:45:01 -0700174 ALOGV("addSession(pid %d, uid %d, drm %p, sessionId %s)", pid, uid, drm.get(),
Tomasz Wasilczyk09977ff2023-08-11 15:52:22 +0000175 GetSessionIdString(sessionId).c_str());
Ronghua Wu10305cc2015-02-22 07:55:32 -0800176
177 Mutex::Autolock lock(mLock);
Robert Shihc3af31b2019-09-20 21:45:01 -0700178 if (mService == NULL) {
179 return;
Ronghua Wu10305cc2015-02-22 07:55:32 -0800180 }
Robert Shihc3af31b2019-09-20 21:45:01 -0700181
Robert Shih0f3a8a02019-11-14 15:43:39 -0800182 static int64_t clientId = 0;
Girish323711f2023-05-24 21:47:34 +0000183 mSessionMap[toStdVec(sessionId)] = (SessionInfo){pid, uid, clientId, drm, INT64_MAX};
Girish9128e242022-11-23 20:52:29 +0000184 ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(pid),
185 .uid = static_cast<int32_t>(uid),
186 .id = clientId++};
187 mService->addResource(clientInfo, drm, toResourceVec(sessionId, INT64_MAX));
Ronghua Wu10305cc2015-02-22 07:55:32 -0800188}
189
190void DrmSessionManager::useSession(const Vector<uint8_t> &sessionId) {
Tomasz Wasilczyk09977ff2023-08-11 15:52:22 +0000191 ALOGV("useSession(%s)", GetSessionIdString(sessionId).c_str());
Ronghua Wu10305cc2015-02-22 07:55:32 -0800192
193 Mutex::Autolock lock(mLock);
Robert Shihc3af31b2019-09-20 21:45:01 -0700194 auto it = mSessionMap.find(toStdVec(sessionId));
195 if (mService == NULL || it == mSessionMap.end()) {
196 return;
Ronghua Wu10305cc2015-02-22 07:55:32 -0800197 }
Robert Shihc3af31b2019-09-20 21:45:01 -0700198
199 auto info = it->second;
Girish323711f2023-05-24 21:47:34 +0000200 info.resourceValue = -1;
Girish9128e242022-11-23 20:52:29 +0000201 ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(info.pid),
202 .uid = static_cast<int32_t>(info.uid),
203 .id = info.clientId};
204 mService->addResource(clientInfo, NULL, toResourceVec(sessionId, -1));
Ronghua Wu10305cc2015-02-22 07:55:32 -0800205}
206
207void DrmSessionManager::removeSession(const Vector<uint8_t> &sessionId) {
Tomasz Wasilczyk09977ff2023-08-11 15:52:22 +0000208 ALOGV("removeSession(%s)", GetSessionIdString(sessionId).c_str());
Ronghua Wu10305cc2015-02-22 07:55:32 -0800209
210 Mutex::Autolock lock(mLock);
Robert Shihc3af31b2019-09-20 21:45:01 -0700211 auto it = mSessionMap.find(toStdVec(sessionId));
212 if (mService == NULL || it == mSessionMap.end()) {
213 return;
Ronghua Wu10305cc2015-02-22 07:55:32 -0800214 }
Ronghua Wu10305cc2015-02-22 07:55:32 -0800215
Robert Shihc3af31b2019-09-20 21:45:01 -0700216 auto info = it->second;
Robert Shihfc62baf2020-03-13 21:49:06 -0700217 // removeClient instead of removeSession because each client has only one session
Girish9128e242022-11-23 20:52:29 +0000218 ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(info.pid),
219 .uid = static_cast<int32_t>(info.uid),
220 .id = info.clientId};
221 mService->removeClient(clientInfo);
Robert Shihc3af31b2019-09-20 21:45:01 -0700222 mSessionMap.erase(it);
Ronghua Wu10305cc2015-02-22 07:55:32 -0800223}
224
225bool DrmSessionManager::reclaimSession(int callingPid) {
226 ALOGV("reclaimSession(%d)", callingPid);
227
Robert Shihc3af31b2019-09-20 21:45:01 -0700228 // unlock early because reclaimResource might callback into removeSession
229 mLock.lock();
Robert Shih0f3a8a02019-11-14 15:43:39 -0800230 std::shared_ptr<IResourceManagerService> service(mService);
Robert Shihc3af31b2019-09-20 21:45:01 -0700231 mLock.unlock();
Ronghua Wu10305cc2015-02-22 07:55:32 -0800232
Robert Shihc3af31b2019-09-20 21:45:01 -0700233 if (service == NULL) {
Ronghua Wu10305cc2015-02-22 07:55:32 -0800234 return false;
235 }
236
Robert Shihc3af31b2019-09-20 21:45:01 -0700237 // cannot update mSessionMap because we do not know which sessionId is reclaimed;
238 // we rely on IResourceManagerClient to removeSession in reclaimResource
Girish9128e242022-11-23 20:52:29 +0000239 Vector<uint8_t> placeHolder;
Chong Zhang181e6952019-10-09 13:23:39 -0700240 bool success;
Girish9128e242022-11-23 20:52:29 +0000241 uid_t uid = AIBinder_getCallingUid();
242 ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(callingPid),
243 .uid = static_cast<int32_t>(uid)};
244 ScopedAStatus status = service->reclaimResource(
245 clientInfo, toResourceVec(placeHolder, INT64_MAX), &success);
Chong Zhang181e6952019-10-09 13:23:39 -0700246 return status.isOk() && success;
Ronghua Wu10305cc2015-02-22 07:55:32 -0800247}
248
Robert Shihc3af31b2019-09-20 21:45:01 -0700249size_t DrmSessionManager::getSessionCount() const {
250 Mutex::Autolock lock(mLock);
251 return mSessionMap.size();
Ronghua Wu10305cc2015-02-22 07:55:32 -0800252}
253
Robert Shihc3af31b2019-09-20 21:45:01 -0700254bool DrmSessionManager::containsSession(const Vector<uint8_t>& sessionId) const {
255 Mutex::Autolock lock(mLock);
256 return mSessionMap.count(toStdVec(sessionId));
Ronghua Wu10305cc2015-02-22 07:55:32 -0800257}
258
Robert Shih0f3a8a02019-11-14 15:43:39 -0800259void DrmSessionManager::binderDied() {
Robert Shihc3af31b2019-09-20 21:45:01 -0700260 ALOGW("ResourceManagerService died.");
261 Mutex::Autolock lock(mLock);
Girish323711f2023-05-24 21:47:34 +0000262 mService = nullptr;
263 mBinderDied = true;
264 // start an async operation that will reconnect with the RM and
265 // re-registers all the resources.
266 mGetServiceFuture = std::async(std::launch::async, [this] { getResourceManagerService(); });
267}
268
269void DrmSessionManager::ResourceManagerServiceDied(void* cookie) {
270 BinderDiedContext* context = reinterpret_cast<BinderDiedContext*>(cookie);
271
272 // Validate the context and check if the DrmSessionManager object is still in scope.
273 if (context != nullptr) {
274 sp<DrmSessionManager> thiz = context->mDrmSessionManager.promote();
275 if (thiz != nullptr) {
276 thiz->binderDied();
277 } else {
278 ALOGI("DrmSessionManager is out of scope already");
279 }
280 }
281}
282
283void DrmSessionManager::BinderUnlinkedCallback(void* cookie) {
284 BinderDiedContext* context = reinterpret_cast<BinderDiedContext*>(cookie);
285 // Since we don't need the context anymore, we are deleting it now.
286 delete context;
Ronghua Wu10305cc2015-02-22 07:55:32 -0800287}
288
289} // namespace android