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