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