blob: 6ac75302c624d65c3b64a454015c104131c4368a [file] [log] [blame]
Jeff Tinkercc82dc62013-02-08 10:18:35 -08001/*
2 * Copyright (C) 2013 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 "Drm"
19#include <utils/Log.h>
20
21#include <dirent.h>
22#include <dlfcn.h>
23
24#include "Drm.h"
25
26#include <media/drm/DrmAPI.h>
27#include <media/stagefright/foundation/ADebug.h>
28#include <media/stagefright/foundation/AString.h>
29#include <media/stagefright/foundation/hexdump.h>
30#include <media/stagefright/MediaErrors.h>
31
32namespace android {
33
34KeyedVector<Vector<uint8_t>, String8> Drm::mUUIDToLibraryPathMap;
35KeyedVector<String8, wp<SharedLibrary> > Drm::mLibraryPathToOpenLibraryMap;
36Mutex Drm::mMapLock;
37
38static bool operator<(const Vector<uint8_t> &lhs, const Vector<uint8_t> &rhs) {
39 if (lhs.size() < rhs.size()) {
40 return true;
41 } else if (lhs.size() > rhs.size()) {
42 return false;
43 }
44
45 return memcmp((void *)lhs.array(), (void *)rhs.array(), rhs.size()) < 0;
46}
47
48Drm::Drm()
49 : mInitCheck(NO_INIT),
50 mFactory(NULL),
51 mPlugin(NULL) {
52}
53
54Drm::~Drm() {
55 delete mPlugin;
56 mPlugin = NULL;
57 closeFactory();
58}
59
60void Drm::closeFactory() {
61 delete mFactory;
62 mFactory = NULL;
63 mLibrary.clear();
64}
65
66status_t Drm::initCheck() const {
67 return mInitCheck;
68}
69
70
71/*
72 * Search the plugins directory for a plugin that supports the scheme
73 * specified by uuid
74 *
75 * If found:
76 * mLibrary holds a strong pointer to the dlopen'd library
77 * mFactory is set to the library's factory method
78 * mInitCheck is set to OK
79 *
80 * If not found:
81 * mLibrary is cleared and mFactory are set to NULL
82 * mInitCheck is set to an error (!OK)
83 */
84void Drm::findFactoryForScheme(const uint8_t uuid[16]) {
85
86 closeFactory();
87
88 // lock static maps
89 Mutex::Autolock autoLock(mMapLock);
90
91 // first check cache
92 Vector<uint8_t> uuidVector;
93 uuidVector.appendArray(uuid, sizeof(uuid));
94 ssize_t index = mUUIDToLibraryPathMap.indexOfKey(uuidVector);
95 if (index >= 0) {
96 if (loadLibraryForScheme(mUUIDToLibraryPathMap[index], uuid)) {
97 mInitCheck = OK;
98 return;
99 } else {
100 ALOGE("Failed to load from cached library path!");
101 mInitCheck = ERROR_UNSUPPORTED;
102 return;
103 }
104 }
105
106 // no luck, have to search
107 String8 dirPath("/vendor/lib/mediadrm");
108 DIR* pDir = opendir(dirPath.string());
109
110 if (pDir == NULL) {
111 mInitCheck = ERROR_UNSUPPORTED;
112 ALOGE("Failed to open plugin directory %s", dirPath.string());
113 return;
114 }
115
116
117 struct dirent* pEntry;
118 while ((pEntry = readdir(pDir))) {
119
120 String8 pluginPath = dirPath + "/" + pEntry->d_name;
121
122 if (pluginPath.getPathExtension() == ".so") {
123
124 if (loadLibraryForScheme(pluginPath, uuid)) {
125 mUUIDToLibraryPathMap.add(uuidVector, pluginPath);
126 mInitCheck = OK;
127 closedir(pDir);
128 return;
129 }
130 }
131 }
132
133 closedir(pDir);
134
135 ALOGE("Failed to find drm plugin");
136 mInitCheck = ERROR_UNSUPPORTED;
137}
138
139bool Drm::loadLibraryForScheme(const String8 &path, const uint8_t uuid[16]) {
140
141 // get strong pointer to open shared library
142 ssize_t index = mLibraryPathToOpenLibraryMap.indexOfKey(path);
143 if (index >= 0) {
144 mLibrary = mLibraryPathToOpenLibraryMap[index].promote();
145 } else {
146 index = mLibraryPathToOpenLibraryMap.add(path, NULL);
147 }
148
149 if (!mLibrary.get()) {
150 mLibrary = new SharedLibrary(path);
151 if (!*mLibrary) {
152 return false;
153 }
154
155 mLibraryPathToOpenLibraryMap.replaceValueAt(index, mLibrary);
156 }
157
158 typedef DrmFactory *(*CreateDrmFactoryFunc)();
159
160 CreateDrmFactoryFunc createDrmFactory =
161 (CreateDrmFactoryFunc)mLibrary->lookup("createDrmFactory");
162
163 if (createDrmFactory == NULL ||
164 (mFactory = createDrmFactory()) == NULL ||
165 !mFactory->isCryptoSchemeSupported(uuid)) {
166 closeFactory();
167 return false;
168 }
169 return true;
170}
171
172bool Drm::isCryptoSchemeSupported(const uint8_t uuid[16]) {
173 Mutex::Autolock autoLock(mLock);
174
175 if (mFactory && mFactory->isCryptoSchemeSupported(uuid)) {
176 return true;
177 }
178
179 findFactoryForScheme(uuid);
180 return (mInitCheck == OK);
181}
182
183status_t Drm::createPlugin(const uint8_t uuid[16]) {
184 Mutex::Autolock autoLock(mLock);
185
186 if (mPlugin != NULL) {
187 return -EINVAL;
188 }
189
190 if (!mFactory || !mFactory->isCryptoSchemeSupported(uuid)) {
191 findFactoryForScheme(uuid);
192 }
193
194 if (mInitCheck != OK) {
195 return mInitCheck;
196 }
197
198 return mFactory->createDrmPlugin(uuid, &mPlugin);
199}
200
201status_t Drm::destroyPlugin() {
202 Mutex::Autolock autoLock(mLock);
203
204 if (mInitCheck != OK) {
205 return mInitCheck;
206 }
207
208 if (mPlugin == NULL) {
209 return -EINVAL;
210 }
211
212 delete mPlugin;
213 mPlugin = NULL;
214
215 return OK;
216}
217
218status_t Drm::openSession(Vector<uint8_t> &sessionId) {
219 Mutex::Autolock autoLock(mLock);
220
221 if (mInitCheck != OK) {
222 return mInitCheck;
223 }
224
225 if (mPlugin == NULL) {
226 return -EINVAL;
227 }
228
229 return mPlugin->openSession(sessionId);
230}
231
232status_t Drm::closeSession(Vector<uint8_t> const &sessionId) {
233 Mutex::Autolock autoLock(mLock);
234
235 if (mInitCheck != OK) {
236 return mInitCheck;
237 }
238
239 if (mPlugin == NULL) {
240 return -EINVAL;
241 }
242
243 return mPlugin->closeSession(sessionId);
244}
245
246status_t Drm::getLicenseRequest(Vector<uint8_t> const &sessionId,
247 Vector<uint8_t> const &initData,
248 String8 const &mimeType, DrmPlugin::LicenseType licenseType,
249 KeyedVector<String8, String8> const &optionalParameters,
250 Vector<uint8_t> &request, String8 &defaultUrl) {
251 Mutex::Autolock autoLock(mLock);
252
253 if (mInitCheck != OK) {
254 return mInitCheck;
255 }
256
257 if (mPlugin == NULL) {
258 return -EINVAL;
259 }
260
261 return mPlugin->getLicenseRequest(sessionId, initData, mimeType, licenseType,
262 optionalParameters, request, defaultUrl);
263}
264
265status_t Drm::provideLicenseResponse(Vector<uint8_t> const &sessionId,
266 Vector<uint8_t> const &response) {
267 Mutex::Autolock autoLock(mLock);
268
269 if (mInitCheck != OK) {
270 return mInitCheck;
271 }
272
273 if (mPlugin == NULL) {
274 return -EINVAL;
275 }
276
277 return mPlugin->provideLicenseResponse(sessionId, response);
278}
279
280status_t Drm::removeLicense(Vector<uint8_t> const &sessionId) {
281 Mutex::Autolock autoLock(mLock);
282
283 if (mInitCheck != OK) {
284 return mInitCheck;
285 }
286
287 if (mPlugin == NULL) {
288 return -EINVAL;
289 }
290
291 return mPlugin->removeLicense(sessionId);
292}
293
294status_t Drm::queryLicenseStatus(Vector<uint8_t> const &sessionId,
295 KeyedVector<String8, String8> &infoMap) const {
296 Mutex::Autolock autoLock(mLock);
297
298 if (mInitCheck != OK) {
299 return mInitCheck;
300 }
301
302 if (mPlugin == NULL) {
303 return -EINVAL;
304 }
305
306 return mPlugin->queryLicenseStatus(sessionId, infoMap);
307}
308
309status_t Drm::getProvisionRequest(Vector<uint8_t> &request, String8 &defaultUrl) {
310 Mutex::Autolock autoLock(mLock);
311
312 if (mInitCheck != OK) {
313 return mInitCheck;
314 }
315
316 if (mPlugin == NULL) {
317 return -EINVAL;
318 }
319
320 return mPlugin->getProvisionRequest(request, defaultUrl);
321}
322
323status_t Drm::provideProvisionResponse(Vector<uint8_t> const &response) {
324 Mutex::Autolock autoLock(mLock);
325
326 if (mInitCheck != OK) {
327 return mInitCheck;
328 }
329
330 if (mPlugin == NULL) {
331 return -EINVAL;
332 }
333
334 return mPlugin->provideProvisionResponse(response);
335}
336
337
338status_t Drm::getSecureStops(List<Vector<uint8_t> > &secureStops) {
339 Mutex::Autolock autoLock(mLock);
340
341 if (mInitCheck != OK) {
342 return mInitCheck;
343 }
344
345 if (mPlugin == NULL) {
346 return -EINVAL;
347 }
348
349 return mPlugin->getSecureStops(secureStops);
350}
351
352status_t Drm::releaseSecureStops(Vector<uint8_t> const &ssRelease) {
353 Mutex::Autolock autoLock(mLock);
354
355 if (mInitCheck != OK) {
356 return mInitCheck;
357 }
358
359 if (mPlugin == NULL) {
360 return -EINVAL;
361 }
362
363 return mPlugin->releaseSecureStops(ssRelease);
364}
365
366status_t Drm::getPropertyString(String8 const &name, String8 &value ) const {
367 Mutex::Autolock autoLock(mLock);
368
369 if (mInitCheck != OK) {
370 return mInitCheck;
371 }
372
373 if (mPlugin == NULL) {
374 return -EINVAL;
375 }
376
377 return mPlugin->getPropertyString(name, value);
378}
379
380status_t Drm::getPropertyByteArray(String8 const &name, Vector<uint8_t> &value ) const {
381 Mutex::Autolock autoLock(mLock);
382
383 if (mInitCheck != OK) {
384 return mInitCheck;
385 }
386
387 if (mPlugin == NULL) {
388 return -EINVAL;
389 }
390
391 return mPlugin->getPropertyByteArray(name, value);
392}
393
394status_t Drm::setPropertyString(String8 const &name, String8 const &value ) const {
395 Mutex::Autolock autoLock(mLock);
396
397 if (mInitCheck != OK) {
398 return mInitCheck;
399 }
400
401 if (mPlugin == NULL) {
402 return -EINVAL;
403 }
404
405 return mPlugin->setPropertyString(name, value);
406}
407
408status_t Drm::setPropertyByteArray(String8 const &name,
409 Vector<uint8_t> const &value ) const {
410 Mutex::Autolock autoLock(mLock);
411
412 if (mInitCheck != OK) {
413 return mInitCheck;
414 }
415
416 if (mPlugin == NULL) {
417 return -EINVAL;
418 }
419
420 return mPlugin->setPropertyByteArray(name, value);
421}
422
423} // namespace android