DrmManager.cpp revision 7f89d09c0f4a47119834ba15789260b933123ea5
1/*
2 * Copyright (C) 2010 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 "DrmManager(Native)"
19#include "utils/Log.h"
20
21#include <utils/String8.h>
22#include <drm/DrmInfo.h>
23#include <drm/DrmInfoEvent.h>
24#include <drm/DrmRights.h>
25#include <drm/DrmConstraints.h>
26#include <drm/DrmMetadata.h>
27#include <drm/DrmInfoStatus.h>
28#include <drm/DrmInfoRequest.h>
29#include <drm/DrmSupportInfo.h>
30#include <drm/DrmConvertedStatus.h>
31#include <IDrmEngine.h>
32
33#include "DrmManager.h"
34#include "ReadWriteUtils.h"
35
36#define DECRYPT_FILE_ERROR -1
37
38using namespace android;
39
40Vector<int> DrmManager::mUniqueIdVector;
41const String8 DrmManager::EMPTY_STRING("");
42
43DrmManager::DrmManager() :
44    mDecryptSessionId(0),
45    mConvertId(0) {
46
47}
48
49DrmManager::~DrmManager() {
50
51}
52
53int DrmManager::addUniqueId(int uniqueId) {
54    if (0 == uniqueId) {
55        int temp = 0;
56        bool foundUniqueId = false;
57        srand(time(NULL));
58
59        while (!foundUniqueId) {
60            const int size = mUniqueIdVector.size();
61            temp = rand() % 100;
62
63            int index = 0;
64            for (; index < size; ++index) {
65                if (mUniqueIdVector.itemAt(index) == temp) {
66                    foundUniqueId = false;
67                    break;
68                }
69            }
70            if (index == size) {
71                foundUniqueId = true;
72            }
73        }
74        uniqueId = temp;
75    }
76    mUniqueIdVector.push(uniqueId);
77    return uniqueId;
78}
79
80void DrmManager::removeUniqueId(int uniqueId) {
81    for (unsigned int i = 0; i < mUniqueIdVector.size(); i++) {
82        if (uniqueId == mUniqueIdVector.itemAt(i)) {
83            mUniqueIdVector.removeAt(i);
84            break;
85        }
86    }
87}
88
89status_t DrmManager::loadPlugIns() {
90    String8 pluginDirPath("/system/lib/drm");
91    return loadPlugIns(pluginDirPath);
92}
93
94status_t DrmManager::loadPlugIns(const String8& plugInDirPath) {
95    if (mSupportInfoToPlugInIdMap.isEmpty()) {
96        mPlugInManager.loadPlugIns(plugInDirPath);
97        Vector<String8> plugInPathList = mPlugInManager.getPlugInIdList();
98        for (unsigned int i = 0; i < plugInPathList.size(); ++i) {
99            String8 plugInPath = plugInPathList[i];
100            DrmSupportInfo* info = mPlugInManager.getPlugIn(plugInPath).getSupportInfo(0);
101            if (NULL != info) {
102                mSupportInfoToPlugInIdMap.add(*info, plugInPath);
103            }
104        }
105    }
106    return DRM_NO_ERROR;
107}
108
109status_t DrmManager::unloadPlugIns() {
110    mConvertSessionMap.clear();
111    mDecryptSessionMap.clear();
112    mPlugInManager.unloadPlugIns();
113    mSupportInfoToPlugInIdMap.clear();
114    return DRM_NO_ERROR;
115}
116
117status_t DrmManager::setDrmServiceListener(
118            int uniqueId, const sp<IDrmServiceListener>& drmServiceListener) {
119    Mutex::Autolock _l(mLock);
120    if (NULL != drmServiceListener.get()) {
121        mServiceListeners.add(uniqueId, drmServiceListener);
122    } else {
123        mServiceListeners.removeItem(uniqueId);
124    }
125    return DRM_NO_ERROR;
126}
127
128void DrmManager::addClient(int uniqueId) {
129    if (!mSupportInfoToPlugInIdMap.isEmpty()) {
130        Vector<String8> plugInIdList = mPlugInManager.getPlugInIdList();
131        for (unsigned int index = 0; index < plugInIdList.size(); index++) {
132            IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInIdList.itemAt(index));
133            rDrmEngine.initialize(uniqueId);
134            rDrmEngine.setOnInfoListener(uniqueId, this);
135        }
136    }
137}
138
139void DrmManager::removeClient(int uniqueId) {
140    Vector<String8> plugInIdList = mPlugInManager.getPlugInIdList();
141    for (unsigned int index = 0; index < plugInIdList.size(); index++) {
142        IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInIdList.itemAt(index));
143        rDrmEngine.terminate(uniqueId);
144    }
145}
146
147DrmConstraints* DrmManager::getConstraints(int uniqueId, const String8* path, const int action) {
148    const String8 plugInId = getSupportedPlugInIdFromPath(uniqueId, *path);
149    if (EMPTY_STRING != plugInId) {
150        IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
151        return rDrmEngine.getConstraints(uniqueId, path, action);
152    }
153    return NULL;
154}
155
156DrmMetadata* DrmManager::getMetadata(int uniqueId, const String8* path) {
157    const String8 plugInId = getSupportedPlugInIdFromPath(uniqueId, *path);
158    if (EMPTY_STRING != plugInId) {
159        IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
160        return rDrmEngine.getMetadata(uniqueId, path);
161    }
162    return NULL;
163}
164
165status_t DrmManager::installDrmEngine(int uniqueId, const String8& absolutePath) {
166    mPlugInManager.loadPlugIn(absolutePath);
167
168    IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(absolutePath);
169    rDrmEngine.initialize(uniqueId);
170    rDrmEngine.setOnInfoListener(uniqueId, this);
171
172    DrmSupportInfo* info = rDrmEngine.getSupportInfo(0);
173    mSupportInfoToPlugInIdMap.add(*info, absolutePath);
174
175    return DRM_NO_ERROR;
176}
177
178bool DrmManager::canHandle(int uniqueId, const String8& path, const String8& mimeType) {
179    const String8 plugInId = getSupportedPlugInId(mimeType);
180    bool result = (EMPTY_STRING != plugInId) ? true : false;
181
182    if (0 < path.length()) {
183        if (result) {
184            IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
185            result = rDrmEngine.canHandle(uniqueId, path);
186        } else {
187            String8 extension = path.getPathExtension();
188            if (String8("") != extension) {
189                result = canHandle(uniqueId, path);
190            }
191        }
192    }
193    return result;
194}
195
196DrmInfoStatus* DrmManager::processDrmInfo(int uniqueId, const DrmInfo* drmInfo) {
197    const String8 plugInId = getSupportedPlugInId(drmInfo->getMimeType());
198    if (EMPTY_STRING != plugInId) {
199        IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
200        return rDrmEngine.processDrmInfo(uniqueId, drmInfo);
201    }
202    return NULL;
203}
204
205bool DrmManager::canHandle(int uniqueId, const String8& path) {
206    bool result = false;
207    Vector<String8> plugInPathList = mPlugInManager.getPlugInIdList();
208
209    for (unsigned int i = 0; i < plugInPathList.size(); ++i) {
210        IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInPathList[i]);
211        result = rDrmEngine.canHandle(uniqueId, path);
212
213        if (result) {
214            break;
215        }
216    }
217    return result;
218}
219
220DrmInfo* DrmManager::acquireDrmInfo(int uniqueId, const DrmInfoRequest* drmInfoRequest) {
221    const String8 plugInId = getSupportedPlugInId(drmInfoRequest->getMimeType());
222    if (EMPTY_STRING != plugInId) {
223        IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
224        return rDrmEngine.acquireDrmInfo(uniqueId, drmInfoRequest);
225    }
226    return NULL;
227}
228
229status_t DrmManager::saveRights(int uniqueId, const DrmRights& drmRights,
230            const String8& rightsPath, const String8& contentPath) {
231    const String8 plugInId = getSupportedPlugInId(drmRights.getMimeType());
232    status_t result = DRM_ERROR_UNKNOWN;
233    if (EMPTY_STRING != plugInId) {
234        IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
235        result = rDrmEngine.saveRights(uniqueId, drmRights, rightsPath, contentPath);
236    }
237    return result;
238}
239
240String8 DrmManager::getOriginalMimeType(int uniqueId, const String8& path) {
241    const String8 plugInId = getSupportedPlugInIdFromPath(uniqueId, path);
242    if (EMPTY_STRING != plugInId) {
243        IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
244        return rDrmEngine.getOriginalMimeType(uniqueId, path);
245    }
246    return EMPTY_STRING;
247}
248
249int DrmManager::getDrmObjectType(int uniqueId, const String8& path, const String8& mimeType) {
250    const String8 plugInId = getSupportedPlugInId(uniqueId, path, mimeType);
251    if (EMPTY_STRING != plugInId) {
252        IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
253        return rDrmEngine.getDrmObjectType(uniqueId, path, mimeType);
254    }
255    return DrmObjectType::UNKNOWN;
256}
257
258int DrmManager::checkRightsStatus(int uniqueId, const String8& path, int action) {
259    const String8 plugInId = getSupportedPlugInIdFromPath(uniqueId, path);
260    if (EMPTY_STRING != plugInId) {
261        IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
262        return rDrmEngine.checkRightsStatus(uniqueId, path, action);
263    }
264    return RightsStatus::RIGHTS_INVALID;
265}
266
267status_t DrmManager::consumeRights(
268    int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve) {
269    status_t result = DRM_ERROR_UNKNOWN;
270    if (mDecryptSessionMap.indexOfKey(decryptHandle->decryptId) != NAME_NOT_FOUND) {
271        IDrmEngine* drmEngine = mDecryptSessionMap.valueFor(decryptHandle->decryptId);
272        result = drmEngine->consumeRights(uniqueId, decryptHandle, action, reserve);
273    }
274    return result;
275}
276
277status_t DrmManager::setPlaybackStatus(
278    int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int64_t position) {
279    status_t result = DRM_ERROR_UNKNOWN;
280    if (mDecryptSessionMap.indexOfKey(decryptHandle->decryptId) != NAME_NOT_FOUND) {
281        IDrmEngine* drmEngine = mDecryptSessionMap.valueFor(decryptHandle->decryptId);
282        result = drmEngine->setPlaybackStatus(uniqueId, decryptHandle, playbackStatus, position);
283    }
284    return result;
285}
286
287bool DrmManager::validateAction(
288    int uniqueId, const String8& path, int action, const ActionDescription& description) {
289    const String8 plugInId = getSupportedPlugInIdFromPath(uniqueId, path);
290    if (EMPTY_STRING != plugInId) {
291        IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
292        return rDrmEngine.validateAction(uniqueId, path, action, description);
293    }
294    return false;
295}
296
297status_t DrmManager::removeRights(int uniqueId, const String8& path) {
298    const String8 plugInId = getSupportedPlugInIdFromPath(uniqueId, path);
299    status_t result = DRM_ERROR_UNKNOWN;
300    if (EMPTY_STRING != plugInId) {
301        IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
302        result = rDrmEngine.removeRights(uniqueId, path);
303    }
304    return result;
305}
306
307status_t DrmManager::removeAllRights(int uniqueId) {
308    Vector<String8> plugInIdList = mPlugInManager.getPlugInIdList();
309    status_t result = DRM_ERROR_UNKNOWN;
310    for (unsigned int index = 0; index < plugInIdList.size(); index++) {
311        IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInIdList.itemAt(index));
312        result = rDrmEngine.removeAllRights(uniqueId);
313        if (DRM_NO_ERROR != result) {
314            break;
315        }
316    }
317    return result;
318}
319
320int DrmManager::openConvertSession(int uniqueId, const String8& mimeType) {
321    int convertId = -1;
322
323    const String8 plugInId = getSupportedPlugInId(mimeType);
324    if (EMPTY_STRING != plugInId) {
325        IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
326
327        if (DRM_NO_ERROR == rDrmEngine.openConvertSession(uniqueId, mConvertId + 1)) {
328            Mutex::Autolock _l(mConvertLock);
329            ++mConvertId;
330            convertId = mConvertId;
331            mConvertSessionMap.add(convertId, &rDrmEngine);
332        }
333    }
334    return convertId;
335}
336
337DrmConvertedStatus* DrmManager::convertData(
338            int uniqueId, int convertId, const DrmBuffer* inputData) {
339    DrmConvertedStatus *drmConvertedStatus = NULL;
340
341    if (mConvertSessionMap.indexOfKey(convertId) != NAME_NOT_FOUND) {
342        IDrmEngine* drmEngine = mConvertSessionMap.valueFor(convertId);
343        drmConvertedStatus = drmEngine->convertData(uniqueId, convertId, inputData);
344    }
345    return drmConvertedStatus;
346}
347
348DrmConvertedStatus* DrmManager::closeConvertSession(int uniqueId, int convertId) {
349    DrmConvertedStatus *drmConvertedStatus = NULL;
350
351    if (mConvertSessionMap.indexOfKey(convertId) != NAME_NOT_FOUND) {
352        IDrmEngine* drmEngine = mConvertSessionMap.valueFor(convertId);
353        drmConvertedStatus = drmEngine->closeConvertSession(uniqueId, convertId);
354        mConvertSessionMap.removeItem(convertId);
355    }
356    return drmConvertedStatus;
357}
358
359status_t DrmManager::getAllSupportInfo(
360                    int uniqueId, int* length, DrmSupportInfo** drmSupportInfoArray) {
361    Vector<String8> plugInPathList = mPlugInManager.getPlugInIdList();
362    int size = plugInPathList.size();
363    int validPlugins = 0;
364
365    if (0 < size) {
366        Vector<DrmSupportInfo> drmSupportInfoList;
367
368        for (int i = 0; i < size; ++i) {
369            String8 plugInPath = plugInPathList[i];
370            DrmSupportInfo* drmSupportInfo
371                = mPlugInManager.getPlugIn(plugInPath).getSupportInfo(0);
372            if (NULL != drmSupportInfo) {
373                drmSupportInfoList.add(*drmSupportInfo);
374                delete drmSupportInfo; drmSupportInfo = NULL;
375            }
376        }
377
378        validPlugins = drmSupportInfoList.size();
379        if (0 < validPlugins) {
380            *drmSupportInfoArray = new DrmSupportInfo[validPlugins];
381            for (int i = 0; i < validPlugins; ++i) {
382                (*drmSupportInfoArray)[i] = drmSupportInfoList[i];
383            }
384        }
385    }
386    *length = validPlugins;
387    return DRM_NO_ERROR;
388}
389
390DecryptHandle* DrmManager::openDecryptSession(int uniqueId, int fd, off64_t offset, off64_t length) {
391    Mutex::Autolock _l(mDecryptLock);
392    status_t result = DRM_ERROR_CANNOT_HANDLE;
393    Vector<String8> plugInIdList = mPlugInManager.getPlugInIdList();
394
395    DecryptHandle* handle = new DecryptHandle();
396    if (NULL != handle) {
397        handle->decryptId = mDecryptSessionId + 1;
398
399        for (unsigned int index = 0; index < plugInIdList.size(); index++) {
400            String8 plugInId = plugInIdList.itemAt(index);
401            IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
402            result = rDrmEngine.openDecryptSession(uniqueId, handle, fd, offset, length);
403
404            if (DRM_NO_ERROR == result) {
405                ++mDecryptSessionId;
406                mDecryptSessionMap.add(mDecryptSessionId, &rDrmEngine);
407                break;
408            }
409        }
410    }
411    if (DRM_NO_ERROR != result) {
412        delete handle; handle = NULL;
413    }
414    return handle;
415}
416
417DecryptHandle* DrmManager::openDecryptSession(int uniqueId, const char* uri) {
418    Mutex::Autolock _l(mDecryptLock);
419    status_t result = DRM_ERROR_CANNOT_HANDLE;
420    Vector<String8> plugInIdList = mPlugInManager.getPlugInIdList();
421
422    DecryptHandle* handle = new DecryptHandle();
423    if (NULL != handle) {
424        handle->decryptId = mDecryptSessionId + 1;
425
426        for (unsigned int index = 0; index < plugInIdList.size(); index++) {
427            String8 plugInId = plugInIdList.itemAt(index);
428            IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
429            result = rDrmEngine.openDecryptSession(uniqueId, handle, uri);
430
431            if (DRM_NO_ERROR == result) {
432                ++mDecryptSessionId;
433                mDecryptSessionMap.add(mDecryptSessionId, &rDrmEngine);
434                break;
435            }
436        }
437    }
438    if (DRM_NO_ERROR != result) {
439        delete handle; handle = NULL;
440        LOGE("DrmManager::openDecryptSession: no capable plug-in found");
441    }
442    return handle;
443}
444
445status_t DrmManager::closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle) {
446    Mutex::Autolock _l(mDecryptLock);
447    status_t result = DRM_ERROR_UNKNOWN;
448    if (mDecryptSessionMap.indexOfKey(decryptHandle->decryptId) != NAME_NOT_FOUND) {
449        IDrmEngine* drmEngine = mDecryptSessionMap.valueFor(decryptHandle->decryptId);
450        result = drmEngine->closeDecryptSession(uniqueId, decryptHandle);
451        if (DRM_NO_ERROR == result) {
452            mDecryptSessionMap.removeItem(decryptHandle->decryptId);
453        }
454    }
455    return result;
456}
457
458status_t DrmManager::initializeDecryptUnit(
459    int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId, const DrmBuffer* headerInfo) {
460    status_t result = DRM_ERROR_UNKNOWN;
461    if (mDecryptSessionMap.indexOfKey(decryptHandle->decryptId) != NAME_NOT_FOUND) {
462        IDrmEngine* drmEngine = mDecryptSessionMap.valueFor(decryptHandle->decryptId);
463        result = drmEngine->initializeDecryptUnit(uniqueId, decryptHandle, decryptUnitId, headerInfo);
464    }
465    return result;
466}
467
468status_t DrmManager::decrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
469            const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) {
470    status_t result = DRM_ERROR_UNKNOWN;
471    if (mDecryptSessionMap.indexOfKey(decryptHandle->decryptId) != NAME_NOT_FOUND) {
472        IDrmEngine* drmEngine = mDecryptSessionMap.valueFor(decryptHandle->decryptId);
473        result = drmEngine->decrypt(
474                uniqueId, decryptHandle, decryptUnitId, encBuffer, decBuffer, IV);
475    }
476    return result;
477}
478
479status_t DrmManager::finalizeDecryptUnit(
480            int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId) {
481    status_t result = DRM_ERROR_UNKNOWN;
482    if (mDecryptSessionMap.indexOfKey(decryptHandle->decryptId) != NAME_NOT_FOUND) {
483        IDrmEngine* drmEngine = mDecryptSessionMap.valueFor(decryptHandle->decryptId);
484        result = drmEngine->finalizeDecryptUnit(uniqueId, decryptHandle, decryptUnitId);
485    }
486    return result;
487}
488
489ssize_t DrmManager::pread(int uniqueId, DecryptHandle* decryptHandle,
490            void* buffer, ssize_t numBytes, off64_t offset) {
491    ssize_t result = DECRYPT_FILE_ERROR;
492
493    if (mDecryptSessionMap.indexOfKey(decryptHandle->decryptId) != NAME_NOT_FOUND) {
494        IDrmEngine* drmEngine = mDecryptSessionMap.valueFor(decryptHandle->decryptId);
495        result = drmEngine->pread(uniqueId, decryptHandle, buffer, numBytes, offset);
496    }
497    return result;
498}
499
500String8 DrmManager::getSupportedPlugInId(
501            int uniqueId, const String8& path, const String8& mimeType) {
502    String8 plugInId("");
503
504    if (EMPTY_STRING != mimeType) {
505        plugInId = getSupportedPlugInId(mimeType);
506    } else {
507        plugInId = getSupportedPlugInIdFromPath(uniqueId, path);
508    }
509    return plugInId;
510}
511
512String8 DrmManager::getSupportedPlugInId(const String8& mimeType) {
513    String8 plugInId("");
514
515    if (EMPTY_STRING != mimeType) {
516        for (unsigned int index = 0; index < mSupportInfoToPlugInIdMap.size(); index++) {
517            const DrmSupportInfo& drmSupportInfo = mSupportInfoToPlugInIdMap.keyAt(index);
518
519            if (drmSupportInfo.isSupportedMimeType(mimeType)) {
520                plugInId = mSupportInfoToPlugInIdMap.valueFor(drmSupportInfo);
521                break;
522            }
523        }
524    }
525    return plugInId;
526}
527
528String8 DrmManager::getSupportedPlugInIdFromPath(int uniqueId, const String8& path) {
529    String8 plugInId("");
530    const String8 fileSuffix = path.getPathExtension();
531
532    for (unsigned int index = 0; index < mSupportInfoToPlugInIdMap.size(); index++) {
533        const DrmSupportInfo& drmSupportInfo = mSupportInfoToPlugInIdMap.keyAt(index);
534
535        if (drmSupportInfo.isSupportedFileSuffix(fileSuffix)) {
536            String8 key = mSupportInfoToPlugInIdMap.valueFor(drmSupportInfo);
537            IDrmEngine& drmEngine = mPlugInManager.getPlugIn(key);
538
539            if (drmEngine.canHandle(uniqueId, path)) {
540                plugInId = key;
541                break;
542            }
543        }
544    }
545    return plugInId;
546}
547
548void DrmManager::onInfo(const DrmInfoEvent& event) {
549    Mutex::Autolock _l(mLock);
550    for (unsigned int index = 0; index < mServiceListeners.size(); index++) {
551        int uniqueId = mServiceListeners.keyAt(index);
552
553        if (uniqueId == event.getUniqueId()) {
554            sp<IDrmServiceListener> serviceListener = mServiceListeners.valueFor(uniqueId);
555            serviceListener->notify(event);
556        }
557    }
558}
559
560