FwdLockEngine.cpp revision 50872c0b6563b75bb02e0de2fd578b40db8227db
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#include "SessionMap.h"
18#include "FwdLockEngine.h"
19#include <utils/Log.h>
20#include <errno.h>
21#include <stdio.h>
22#include <unistd.h>
23#include "drm_framework_common.h"
24#include <fcntl.h>
25#include <limits.h>
26#include <DrmRights.h>
27#include <DrmConstraints.h>
28#include <DrmMetadata.h>
29#include <DrmInfo.h>
30#include <DrmInfoStatus.h>
31#include <DrmInfoRequest.h>
32#include <DrmSupportInfo.h>
33#include <DrmConvertedStatus.h>
34#include <utils/String8.h>
35#include "FwdLockConv.h"
36#include "FwdLockFile.h"
37#include "FwdLockGlue.h"
38#include "FwdLockEngineConst.h"
39#include "MimeTypeUtil.h"
40
41#undef LOG_TAG
42#define LOG_TAG "FwdLockEngine"
43
44using namespace android;
45// This extern "C" is mandatory to be managed by TPlugInManager
46extern "C" IDrmEngine* create() {
47    return new FwdLockEngine();
48}
49
50// This extern "C" is mandatory to be managed by TPlugInManager
51extern "C" void destroy(IDrmEngine* plugIn) {
52    delete plugIn;
53}
54
55FwdLockEngine::FwdLockEngine() {
56    LOGD("FwdLockEngine Construction");
57}
58
59FwdLockEngine::~FwdLockEngine() {
60    LOGD("FwdLockEngine Destruction");
61
62    convertSessionMap.destroyMap();
63    decodeSessionMap.destroyMap();
64}
65
66int FwdLockEngine::getConvertedStatus(FwdLockConv_Status_t status) {
67    int retStatus = DrmConvertedStatus::STATUS_ERROR;
68
69    switch(status) {
70        case FwdLockConv_Status_OK:
71            retStatus = DrmConvertedStatus::STATUS_OK;
72            break;
73        case FwdLockConv_Status_SyntaxError:
74        case FwdLockConv_Status_InvalidArgument:
75        case FwdLockConv_Status_UnsupportedFileFormat:
76        case FwdLockConv_Status_UnsupportedContentTransferEncoding:
77            LOGD("FwdLockEngine getConvertedStatus: file conversion Error %d. " \
78                  "Returning STATUS_INPUTDATA_ERROR", status);
79            retStatus = DrmConvertedStatus::STATUS_INPUTDATA_ERROR;
80            break;
81        default:
82            LOGD("FwdLockEngine getConvertedStatus: file conversion Error %d. " \
83                  "Returning STATUS_ERROR", status);
84            retStatus = DrmConvertedStatus::STATUS_ERROR;
85            break;
86    }
87
88    return retStatus;
89}
90
91DrmConstraints* FwdLockEngine::onGetConstraints(int uniqueId, const String8* path, int action) {
92    DrmConstraints* drmConstraints = NULL;
93
94    LOGD("FwdLockEngine::onGetConstraints");
95
96    if (NULL != path &&
97        (RightsStatus::RIGHTS_VALID == onCheckRightsStatus(uniqueId, *path, action))) {
98        // Return the empty constraints to show no error condition.
99        drmConstraints = new DrmConstraints();
100    }
101
102    return drmConstraints;
103}
104
105DrmMetadata* FwdLockEngine::onGetMetadata(int uniqueId, const String8* path) {
106    DrmMetadata* drmMetadata = NULL;
107
108    LOGD("FwdLockEngine::onGetMetadata");
109
110    if (NULL != path) {
111        // Returns empty metadata to show no error condition.
112        drmMetadata = new DrmMetadata();
113    }
114
115    return drmMetadata;
116}
117
118android::status_t FwdLockEngine::onInitialize(int uniqueId) {
119    LOGD("FwdLockEngine::onInitialize");
120
121
122    if (FwdLockGlue_InitializeKeyEncryption()) {
123        LOGD("FwdLockEngine::onInitialize -- FwdLockGlue_InitializeKeyEncryption succeeded");
124    } else {
125        LOGD("FwdLockEngine::onInitialize -- FwdLockGlue_InitializeKeyEncryption failed:"
126             "errno = %d", errno);
127    }
128
129    return DRM_NO_ERROR;
130}
131
132android::status_t
133FwdLockEngine::onSetOnInfoListener(int uniqueId, const IDrmEngine::OnInfoListener* infoListener) {
134    // Not used
135    LOGD("FwdLockEngine::onSetOnInfoListener");
136
137    return DRM_NO_ERROR;
138}
139
140android::status_t FwdLockEngine::onTerminate(int uniqueId) {
141    LOGD("FwdLockEngine::onTerminate");
142
143    return DRM_NO_ERROR;
144}
145
146DrmSupportInfo* FwdLockEngine::onGetSupportInfo(int uniqueId) {
147    DrmSupportInfo* pSupportInfo = new DrmSupportInfo();
148
149    LOGD("FwdLockEngine::onGetSupportInfo");
150
151    // fill all Forward Lock mimetypes and extensions
152    if (NULL != pSupportInfo) {
153        pSupportInfo->addMimeType(String8(FWDLOCK_MIMETYPE_FL));
154        pSupportInfo->addFileSuffix(String8(FWDLOCK_DOTEXTENSION_FL));
155        pSupportInfo->addMimeType(String8(FWDLOCK_MIMETYPE_DM));
156        pSupportInfo->addFileSuffix(String8(FWDLOCK_DOTEXTENSION_DM));
157
158        pSupportInfo->setDescription(String8(FWDLOCK_DESCRIPTION));
159    }
160
161    return pSupportInfo;
162}
163
164bool FwdLockEngine::onCanHandle(int uniqueId, const String8& path) {
165    bool result = false;
166
167    String8 extString = path.getPathExtension();
168
169    extString.toLower();
170
171    if ((extString == String8(FWDLOCK_DOTEXTENSION_FL)) ||
172        (extString == String8(FWDLOCK_DOTEXTENSION_DM))) {
173        result = true;
174    }
175    return result;
176}
177
178DrmInfoStatus* FwdLockEngine::onProcessDrmInfo(int uniqueId, const DrmInfo* drmInfo) {
179    DrmInfoStatus *drmInfoStatus = NULL;
180
181    // Nothing to process
182
183    drmInfoStatus = new DrmInfoStatus((int)DrmInfoStatus::STATUS_OK, 0, NULL, String8(""));
184
185    LOGD("FwdLockEngine::onProcessDrmInfo");
186
187    return drmInfoStatus;
188}
189
190status_t FwdLockEngine::onSaveRights(
191            int uniqueId,
192            const DrmRights& drmRights,
193            const String8& rightsPath,
194            const String8& contentPath) {
195    // No rights to save. Return
196    LOGD("FwdLockEngine::onSaveRights");
197    return DRM_ERROR_UNKNOWN;
198}
199
200DrmInfo* FwdLockEngine::onAcquireDrmInfo(int uniqueId, const DrmInfoRequest* drmInfoRequest) {
201    DrmInfo* drmInfo = NULL;
202
203    // Nothing to be done for Forward Lock file
204    LOGD("FwdLockEngine::onAcquireDrmInfo");
205
206    return drmInfo;
207}
208
209int FwdLockEngine::onCheckRightsStatus(int uniqueId,
210                                       const String8& path,
211                                       int action) {
212    int result = RightsStatus::RIGHTS_INVALID;
213
214    LOGD("FwdLockEngine::onCheckRightsStatus");
215
216    // Only Transfer action is not allowed for forward Lock files.
217    if (onCanHandle(uniqueId, path)) {
218        switch(action) {
219            case Action::DEFAULT:
220            case Action::PLAY:
221            case Action::RINGTONE:
222            case Action::OUTPUT:
223            case Action::PREVIEW:
224            case Action::EXECUTE:
225            case Action::DISPLAY:
226                result = RightsStatus::RIGHTS_VALID;
227                break;
228
229            case Action::TRANSFER:
230            default:
231                result = RightsStatus::RIGHTS_INVALID;
232                break;
233        }
234    }
235
236    return result;
237}
238
239status_t FwdLockEngine::onConsumeRights(int uniqueId,
240                                        DecryptHandle* decryptHandle,
241                                        int action,
242                                        bool reserve) {
243    // No rights consumption
244    LOGD("FwdLockEngine::onConsumeRights");
245    return DRM_NO_ERROR;
246}
247
248bool FwdLockEngine::onValidateAction(int uniqueId,
249                                     const String8& path,
250                                     int action,
251                                     const ActionDescription& description) {
252    LOGD("FwdLockEngine::onValidateAction");
253
254    // For the forwardlock engine checkRights and ValidateAction are the same.
255    return (onCheckRightsStatus(uniqueId, path, action) == RightsStatus::RIGHTS_VALID);
256}
257
258String8 FwdLockEngine::onGetOriginalMimeType(int uniqueId, const String8& path) {
259    LOGD("FwdLockEngine::onGetOriginalMimeType");
260    String8 mimeString = String8("");
261    int fileDesc = FwdLockFile_open(path.string());
262
263    if (-1 < fileDesc) {
264        const char* pMimeType = FwdLockFile_GetContentType(fileDesc);
265
266        if (NULL != pMimeType) {
267            String8 contentType = String8(pMimeType);
268            contentType.toLower();
269            mimeString = MimeTypeUtil::convertMimeType(contentType);
270        }
271
272        FwdLockFile_close(fileDesc);
273    }
274
275    return mimeString;
276}
277
278int FwdLockEngine::onGetDrmObjectType(int uniqueId,
279                                      const String8& path,
280                                      const String8& mimeType) {
281    String8 mimeStr = String8(mimeType);
282
283    LOGD("FwdLockEngine::onGetDrmObjectType");
284
285    mimeStr.toLower();
286
287    /* Checks whether
288    * 1. path and mime type both are not empty strings (meaning unavailable) else content is unknown
289    * 2. if one of them is empty string and if other is known then its a DRM Content Object.
290    * 3. if both of them are available, then both may be of known type
291    *    (regardless of the relation between them to make it compatible with other DRM Engines)
292    */
293    if (((0 == path.length()) || onCanHandle(uniqueId, path)) &&
294        ((0 == mimeType.length()) || ((mimeStr == String8(FWDLOCK_MIMETYPE_FL)) ||
295        (mimeStr == String8(FWDLOCK_MIMETYPE_DM)))) && (mimeType != path) ) {
296            return DrmObjectType::CONTENT;
297    }
298
299    return DrmObjectType::UNKNOWN;
300}
301
302status_t FwdLockEngine::onRemoveRights(int uniqueId, const String8& path) {
303    // No Rights to remove
304    LOGD("FwdLockEngine::onRemoveRights");
305    return DRM_NO_ERROR;
306}
307
308status_t FwdLockEngine::onRemoveAllRights(int uniqueId) {
309    // No rights to remove
310    LOGD("FwdLockEngine::onRemoveAllRights");
311    return DRM_NO_ERROR;
312}
313
314#ifdef USE_64BIT_DRM_API
315status_t FwdLockEngine::onSetPlaybackStatus(int uniqueId, DecryptHandle* decryptHandle,
316                                            int playbackStatus, int64_t position) {
317#else
318status_t FwdLockEngine::onSetPlaybackStatus(int uniqueId, DecryptHandle* decryptHandle,
319                                            int playbackStatus, int position) {
320#endif
321    // Not used
322    LOGD("FwdLockEngine::onSetPlaybackStatus");
323    return DRM_NO_ERROR;
324}
325
326status_t FwdLockEngine::onOpenConvertSession(int uniqueId,
327                                         int convertId) {
328    status_t result = DRM_ERROR_UNKNOWN;
329    LOGD("FwdLockEngine::onOpenConvertSession");
330    if (!convertSessionMap.isCreated(convertId)) {
331        ConvertSession *newSession = new ConvertSession();
332        if (FwdLockConv_Status_OK ==
333            FwdLockConv_OpenSession(&(newSession->uniqueId), &(newSession->output))) {
334            convertSessionMap.addValue(convertId, newSession);
335            result = DRM_NO_ERROR;
336        } else {
337            LOGD("FwdLockEngine::onOpenConvertSession -- FwdLockConv_OpenSession failed.");
338            delete newSession;
339        }
340    }
341    return result;
342}
343
344DrmConvertedStatus* FwdLockEngine::onConvertData(int uniqueId,
345                                                 int convertId,
346                                                 const DrmBuffer* inputData) {
347    FwdLockConv_Status_t retStatus = FwdLockConv_Status_InvalidArgument;
348    DrmBuffer *convResult = new DrmBuffer(NULL, 0);
349    int offset = -1;
350
351    if (NULL != inputData && convertSessionMap.isCreated(convertId)) {
352        ConvertSession *convSession = convertSessionMap.getValue(convertId);
353
354        if (NULL != convSession) {
355            retStatus = FwdLockConv_ConvertData(convSession->uniqueId,
356                                                inputData->data,
357                                                inputData->length,
358                                                &(convSession->output));
359
360            if (FwdLockConv_Status_OK == retStatus) {
361                // return bytes from conversion if available
362                if (convSession->output.fromConvertData.numBytes > 0) {
363                    convResult->data = new char[convSession->output.fromConvertData.numBytes];
364
365                    if (NULL != convResult->data) {
366                        convResult->length = convSession->output.fromConvertData.numBytes;
367                        memcpy(convResult->data,
368                               (char *)convSession->output.fromConvertData.pBuffer,
369                               convResult->length);
370                    }
371                }
372            } else {
373                offset = convSession->output.fromConvertData.errorPos;
374            }
375        }
376    }
377    return new DrmConvertedStatus(getConvertedStatus(retStatus), convResult, offset);
378}
379
380DrmConvertedStatus* FwdLockEngine::onCloseConvertSession(int uniqueId,
381                                                         int convertId) {
382    FwdLockConv_Status_t retStatus = FwdLockConv_Status_InvalidArgument;
383    DrmBuffer *convResult = new DrmBuffer(NULL, 0);
384    int offset = -1;
385
386    LOGD("FwdLockEngine::onCloseConvertSession");
387
388    if (convertSessionMap.isCreated(convertId)) {
389        ConvertSession *convSession = convertSessionMap.getValue(convertId);
390
391        if (NULL != convSession) {
392            retStatus = FwdLockConv_CloseSession(convSession->uniqueId, &(convSession->output));
393
394            if (FwdLockConv_Status_OK == retStatus) {
395                offset = convSession->output.fromCloseSession.fileOffset;
396                convResult->data = new char[FWD_LOCK_SIGNATURES_SIZE];
397
398                if (NULL != convResult->data) {
399                      convResult->length = FWD_LOCK_SIGNATURES_SIZE;
400                      memcpy(convResult->data,
401                             (char *)convSession->output.fromCloseSession.signatures,
402                             convResult->length);
403                }
404            }
405        }
406        convertSessionMap.removeValue(convertId);
407    }
408    return new DrmConvertedStatus(getConvertedStatus(retStatus), convResult, offset);
409}
410
411#ifdef USE_64BIT_DRM_API
412status_t FwdLockEngine::onOpenDecryptSession(int uniqueId,
413                                             DecryptHandle* decryptHandle,
414                                             int fd,
415                                             off64_t offset,
416                                             off64_t length) {
417#else
418status_t FwdLockEngine::onOpenDecryptSession(int uniqueId,
419                                             DecryptHandle* decryptHandle,
420                                             int fd,
421                                             int offset,
422                                             int length) {
423#endif
424    status_t result = DRM_ERROR_CANNOT_HANDLE;
425    int fileDesc = -1;
426
427    LOGD("FwdLockEngine::onOpenDecryptSession");
428
429    if ((-1 < fd) &&
430        (NULL != decryptHandle) &&
431        (!decodeSessionMap.isCreated(decryptHandle->decryptId))) {
432        fileDesc = dup(fd);
433    } else {
434        LOGD("FwdLockEngine::onOpenDecryptSession parameter error");
435        return result;
436    }
437
438    if (-1 < fileDesc &&
439        -1 < ::lseek(fileDesc, offset, SEEK_SET) &&
440        -1 < FwdLockFile_attach(fileDesc)) {
441        // check for file integrity. This must be done to protect the content mangling.
442        int retVal = FwdLockFile_CheckHeaderIntegrity(fileDesc);
443        DecodeSession* decodeSession = new DecodeSession(fileDesc);
444
445        if (retVal && NULL != decodeSession) {
446            decodeSessionMap.addValue(decryptHandle->decryptId, decodeSession);
447            const char *pmime= FwdLockFile_GetContentType(fileDesc);
448            String8 contentType = String8(pmime == NULL ? "" : pmime);
449            contentType.toLower();
450            decryptHandle->mimeType = MimeTypeUtil::convertMimeType(contentType);
451            decryptHandle->decryptApiType = DecryptApiType::CONTAINER_BASED;
452            decryptHandle->status = RightsStatus::RIGHTS_VALID;
453            decryptHandle->decryptInfo = NULL;
454            result = DRM_NO_ERROR;
455        } else {
456            LOGD("FwdLockEngine::onOpenDecryptSession Integrity Check failed for the fd");
457            FwdLockFile_detach(fileDesc);
458            delete decodeSession;
459        }
460    }
461
462    if (DRM_NO_ERROR != result && -1 < fileDesc) {
463        ::close(fileDesc);
464    }
465
466    LOGD("FwdLockEngine::onOpenDecryptSession Exit. result = %d", result);
467
468    return result;
469}
470
471status_t FwdLockEngine::onOpenDecryptSession(int uniqueId,
472                                             DecryptHandle* decryptHandle,
473                                             const char* uri) {
474    status_t result = DRM_ERROR_CANNOT_HANDLE;
475    const char fileTag [] = "file://";
476
477    if (NULL != decryptHandle && NULL != uri && strlen(uri) > sizeof(fileTag)) {
478        String8 uriTag = String8(uri);
479        uriTag.toLower();
480
481        if (0 == strncmp(uriTag.string(), fileTag, sizeof(fileTag) - 1)) {
482            const char *filePath = strchr(uri + sizeof(fileTag) - 1, '/');
483            if (NULL != filePath && onCanHandle(uniqueId, String8(filePath))) {
484                int fd = open(filePath, O_RDONLY);
485
486                if (-1 < fd) {
487                    // offset is always 0 and length is not used. so any positive size.
488                    result = onOpenDecryptSession(uniqueId, decryptHandle, fd, 0, 1);
489
490                    // fd is duplicated already if success. closing the file
491                    close(fd);
492                }
493            }
494        }
495    }
496
497    return result;
498}
499
500status_t FwdLockEngine::onCloseDecryptSession(int uniqueId,
501                                              DecryptHandle* decryptHandle) {
502    status_t result = DRM_ERROR_UNKNOWN;
503    LOGD("FwdLockEngine::onCloseDecryptSession");
504
505    if (NULL != decryptHandle && decodeSessionMap.isCreated(decryptHandle->decryptId)) {
506        DecodeSession* session = decodeSessionMap.getValue(decryptHandle->decryptId);
507        if (NULL != session && session->fileDesc > -1) {
508            FwdLockFile_detach(session->fileDesc);
509            ::close(session->fileDesc);
510            decodeSessionMap.removeValue(decryptHandle->decryptId);
511            result = DRM_NO_ERROR;
512        }
513    }
514
515    LOGD("FwdLockEngine::onCloseDecryptSession Exit");
516    return result;
517}
518
519status_t FwdLockEngine::onInitializeDecryptUnit(int uniqueId,
520                                                DecryptHandle* decryptHandle,
521                                                int decryptUnitId,
522                                                const DrmBuffer* headerInfo) {
523    LOGD("FwdLockEngine::onInitializeDecryptUnit");
524    return DRM_ERROR_UNKNOWN;
525}
526
527status_t FwdLockEngine::onDecrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
528            const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) {
529    LOGD("FwdLockEngine::onDecrypt");
530    return DRM_ERROR_UNKNOWN;
531}
532
533status_t FwdLockEngine::onDecrypt(int uniqueId,
534                                  DecryptHandle* decryptHandle,
535                                  int decryptUnitId,
536                                  const DrmBuffer* encBuffer,
537                                  DrmBuffer** decBuffer) {
538    LOGD("FwdLockEngine::onDecrypt");
539    return DRM_ERROR_UNKNOWN;
540}
541
542status_t FwdLockEngine::onFinalizeDecryptUnit(int uniqueId,
543                                              DecryptHandle* decryptHandle,
544                                              int decryptUnitId) {
545    LOGD("FwdLockEngine::onFinalizeDecryptUnit");
546    return DRM_ERROR_UNKNOWN;
547}
548
549ssize_t FwdLockEngine::onRead(int uniqueId,
550                              DecryptHandle* decryptHandle,
551                              void* buffer,
552                              int numBytes) {
553    ssize_t size = -1;
554
555    if (NULL != decryptHandle &&
556       decodeSessionMap.isCreated(decryptHandle->decryptId) &&
557        NULL != buffer &&
558        numBytes > -1) {
559        DecodeSession* session = decodeSessionMap.getValue(decryptHandle->decryptId);
560        if (NULL != session && session->fileDesc > -1) {
561            size = FwdLockFile_read(session->fileDesc, buffer, numBytes);
562
563            if (0 > size) {
564                session->offset = ((off_t)-1);
565            } else {
566                session->offset += size;
567            }
568        }
569    }
570
571    return size;
572}
573
574#ifdef USE_64BIT_DRM_API
575off64_t FwdLockEngine::onLseek(int uniqueId, DecryptHandle* decryptHandle,
576                               off64_t offset, int whence) {
577#else
578off_t FwdLockEngine::onLseek(int uniqueId, DecryptHandle* decryptHandle,
579                             off_t offset, int whence) {
580#endif
581    off_t offval = -1;
582
583    if (NULL != decryptHandle && decodeSessionMap.isCreated(decryptHandle->decryptId)) {
584        DecodeSession* session = decodeSessionMap.getValue(decryptHandle->decryptId);
585        if (NULL != session && session->fileDesc > -1) {
586            offval = FwdLockFile_lseek(session->fileDesc, offset, whence);
587            session->offset = offval;
588        }
589    }
590
591    return offval;
592}
593
594#ifdef USE_64BIT_DRM_API
595ssize_t FwdLockEngine::onPread(int uniqueId,
596                               DecryptHandle* decryptHandle,
597                               void* buffer,
598                               ssize_t numBytes,
599                               off64_t offset) {
600#else
601ssize_t FwdLockEngine::onPread(int uniqueId,
602                               DecryptHandle* decryptHandle,
603                               void* buffer,
604                               ssize_t numBytes,
605                               off_t offset) {
606#endif
607    ssize_t bytesRead = -1;
608
609    DecodeSession* decoderSession = NULL;
610
611    if ((NULL != decryptHandle) &&
612        (NULL != (decoderSession = decodeSessionMap.getValue(decryptHandle->decryptId))) &&
613        (NULL != buffer) &&
614        (numBytes > -1) &&
615        (offset > -1)) {
616        if (offset != decoderSession->offset) {
617            decoderSession->offset = onLseek(uniqueId, decryptHandle, offset, SEEK_SET);
618        }
619
620        if (((off_t)-1) != decoderSession->offset) {
621            bytesRead = onRead(uniqueId, decryptHandle, buffer, numBytes);
622            if (bytesRead < 0) {
623                LOGD("FwdLockEngine::onPread error reading");
624            }
625        }
626    } else {
627        LOGD("FwdLockEngine::onPread decryptId not found");
628    }
629
630    return bytesRead;
631}
632