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