FwdLockEngine.cpp revision fdd65a0fc7df2c878cc601e4c0f4021cb264f051
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            ::close(fileDesc);
459            delete decodeSession;
460        }
461    }
462
463    LOGD("FwdLockEngine::onOpenDecryptSession Exit. result = %d", result);
464
465    return result;
466}
467
468status_t FwdLockEngine::onOpenDecryptSession(int uniqueId,
469                                             DecryptHandle* decryptHandle,
470                                             const char* uri) {
471    status_t result = DRM_ERROR_CANNOT_HANDLE;
472    const char fileTag [] = "file://";
473
474    if (NULL != decryptHandle && NULL != uri && strlen(uri) > sizeof(fileTag)) {
475        String8 uriTag = String8(uri);
476        uriTag.toLower();
477
478        if (0 == strncmp(uriTag.string(), fileTag, sizeof(fileTag) - 1)) {
479            const char *filePath = strchr(uri + sizeof(fileTag) - 1, '/');
480            if (NULL != filePath && onCanHandle(uniqueId, String8(filePath))) {
481                int fd = open(filePath, O_RDONLY);
482
483                if (-1 < fd) {
484                    // offset is always 0 and length is not used. so any positive size.
485                    result = onOpenDecryptSession(uniqueId, decryptHandle, fd, 0, 1);
486
487                    // fd is duplicated already if success. closing the file
488                    close(fd);
489                }
490            }
491        }
492    }
493
494    return result;
495}
496
497status_t FwdLockEngine::onCloseDecryptSession(int uniqueId,
498                                              DecryptHandle* decryptHandle) {
499    status_t result = DRM_ERROR_UNKNOWN;
500    LOGD("FwdLockEngine::onCloseDecryptSession");
501
502    if (NULL != decryptHandle && decodeSessionMap.isCreated(decryptHandle->decryptId)) {
503        DecodeSession* session = decodeSessionMap.getValue(decryptHandle->decryptId);
504        if (NULL != session && session->fileDesc > -1) {
505            FwdLockFile_detach(session->fileDesc);
506            ::close(session->fileDesc);
507            decodeSessionMap.removeValue(decryptHandle->decryptId);
508            result = DRM_NO_ERROR;
509        }
510    }
511
512    LOGD("FwdLockEngine::onCloseDecryptSession Exit");
513    return result;
514}
515
516status_t FwdLockEngine::onInitializeDecryptUnit(int uniqueId,
517                                                DecryptHandle* decryptHandle,
518                                                int decryptUnitId,
519                                                const DrmBuffer* headerInfo) {
520    LOGD("FwdLockEngine::onInitializeDecryptUnit");
521    return DRM_ERROR_UNKNOWN;
522}
523
524status_t FwdLockEngine::onDecrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
525            const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) {
526    LOGD("FwdLockEngine::onDecrypt");
527    return DRM_ERROR_UNKNOWN;
528}
529
530status_t FwdLockEngine::onDecrypt(int uniqueId,
531                                  DecryptHandle* decryptHandle,
532                                  int decryptUnitId,
533                                  const DrmBuffer* encBuffer,
534                                  DrmBuffer** decBuffer) {
535    LOGD("FwdLockEngine::onDecrypt");
536    return DRM_ERROR_UNKNOWN;
537}
538
539status_t FwdLockEngine::onFinalizeDecryptUnit(int uniqueId,
540                                              DecryptHandle* decryptHandle,
541                                              int decryptUnitId) {
542    LOGD("FwdLockEngine::onFinalizeDecryptUnit");
543    return DRM_ERROR_UNKNOWN;
544}
545
546ssize_t FwdLockEngine::onRead(int uniqueId,
547                              DecryptHandle* decryptHandle,
548                              void* buffer,
549                              int numBytes) {
550    ssize_t size = -1;
551
552    if (NULL != decryptHandle &&
553       decodeSessionMap.isCreated(decryptHandle->decryptId) &&
554        NULL != buffer &&
555        numBytes > -1) {
556        DecodeSession* session = decodeSessionMap.getValue(decryptHandle->decryptId);
557        if (NULL != session && session->fileDesc > -1) {
558            size = FwdLockFile_read(session->fileDesc, buffer, numBytes);
559
560            if (0 > size) {
561                session->offset = ((off_t)-1);
562            } else {
563                session->offset += size;
564            }
565        }
566    }
567
568    return size;
569}
570
571#ifdef USE_64BIT_DRM_API
572off64_t FwdLockEngine::onLseek(int uniqueId, DecryptHandle* decryptHandle,
573                               off64_t offset, int whence) {
574#else
575off_t FwdLockEngine::onLseek(int uniqueId, DecryptHandle* decryptHandle,
576                             off_t offset, int whence) {
577#endif
578    off_t offval = -1;
579
580    if (NULL != decryptHandle && decodeSessionMap.isCreated(decryptHandle->decryptId)) {
581        DecodeSession* session = decodeSessionMap.getValue(decryptHandle->decryptId);
582        if (NULL != session && session->fileDesc > -1) {
583            offval = FwdLockFile_lseek(session->fileDesc, offset, whence);
584            session->offset = offval;
585        }
586    }
587
588    return offval;
589}
590
591#ifdef USE_64BIT_DRM_API
592ssize_t FwdLockEngine::onPread(int uniqueId,
593                               DecryptHandle* decryptHandle,
594                               void* buffer,
595                               ssize_t numBytes,
596                               off64_t offset) {
597#else
598ssize_t FwdLockEngine::onPread(int uniqueId,
599                               DecryptHandle* decryptHandle,
600                               void* buffer,
601                               ssize_t numBytes,
602                               off_t offset) {
603#endif
604    ssize_t bytesRead = -1;
605
606    DecodeSession* decoderSession = NULL;
607
608    if ((NULL != decryptHandle) &&
609        (NULL != (decoderSession = decodeSessionMap.getValue(decryptHandle->decryptId))) &&
610        (NULL != buffer) &&
611        (numBytes > -1) &&
612        (offset > -1)) {
613        if (offset != decoderSession->offset) {
614            decoderSession->offset = onLseek(uniqueId, decryptHandle, offset, SEEK_SET);
615        }
616
617        if (((off_t)-1) != decoderSession->offset) {
618            bytesRead = onRead(uniqueId, decryptHandle, buffer, numBytes);
619            if (bytesRead < 0) {
620                LOGD("FwdLockEngine::onPread error reading");
621            }
622        }
623    } else {
624        LOGD("FwdLockEngine::onPread decryptId not found");
625    }
626
627    return bytesRead;
628}
629