Drm.cpp revision cc82dc6d500023eba6048616301a4b12682458db
1/*
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
424