static jobjectArray android_drm_DrmManagerClient_getAllSupportInfo(
            JNIEnv* env, jobject thiz, jint uniqueId) {
    ALOGV("GetAllSupportInfo - Enter");
    DrmSupportInfo* drmSupportInfoArray = NULL;

    int length = 0;
    getDrmManagerClientImpl(env, thiz)->getAllSupportInfo(uniqueId, &length, &drmSupportInfoArray);

    jclass clazz = env->FindClass("android/drm/DrmSupportInfo");

    jobjectArray array = (jobjectArray)env->NewObjectArray(length, clazz, NULL);

    for (int i = 0; i < length; i++) {
        DrmSupportInfo info = drmSupportInfoArray[i];

        jobject drmSupportInfo = env->NewObject(clazz, env->GetMethodID(clazz, "<init>", "()V"));

        jmethodID addMimeTypeId
            = env->GetMethodID(clazz, "addMimeType", "(Ljava/lang/String;)V");
        jmethodID addFileSuffixId
            = env->GetMethodID(clazz, "addFileSuffix", "(Ljava/lang/String;)V");

        env->CallVoidMethod(
            drmSupportInfo, env->GetMethodID(clazz, "setDescription", "(Ljava/lang/String;)V"),
            env->NewStringUTF(info.getDescription().string()));

        DrmSupportInfo::MimeTypeIterator iterator = info.getMimeTypeIterator();
        while (iterator.hasNext()) {
            String8  value = iterator.next();
            env->CallVoidMethod(drmSupportInfo, addMimeTypeId, env->NewStringUTF(value.string()));
        }

        DrmSupportInfo::FileSuffixIterator it = info.getFileSuffixIterator();
        while (it.hasNext()) {
            String8 value = it.next();
            env->CallVoidMethod(
                drmSupportInfo, addFileSuffixId, env->NewStringUTF(value.string()));
        }

        env->SetObjectArrayElement(array, i, drmSupportInfo);
    }

    delete [] drmSupportInfoArray; drmSupportInfoArray = NULL;
    ALOGV("GetAllSupportInfo - Exit");
    return array;
}
status_t BnDrmManagerService::onTransact(
            uint32_t code, const Parcel& data,
            Parcel* reply, uint32_t flags) {
    LOGV("Entering BnDrmManagerService::onTransact with code %d", code);

    switch (code) {
    case ADD_UNIQUEID:
    {
        LOGV("BnDrmManagerService::onTransact :ADD_UNIQUEID");
        CHECK_INTERFACE(IDrmManagerService, data, reply);
        int uniqueId = addUniqueId(data.readInt32());
        reply->writeInt32(uniqueId);
        return DRM_NO_ERROR;
    }

    case REMOVE_UNIQUEID:
    {
        LOGV("BnDrmManagerService::onTransact :REMOVE_UNIQUEID");
        CHECK_INTERFACE(IDrmManagerService, data, reply);
        removeUniqueId(data.readInt32());
        return DRM_NO_ERROR;
    }

    case LOAD_PLUGINS:
    {
        LOGV("BnDrmManagerService::onTransact :LOAD_PLUGINS");
        CHECK_INTERFACE(IDrmManagerService, data, reply);

        status_t status = loadPlugIns(data.readInt32());

        reply->writeInt32(status);
        return DRM_NO_ERROR;
    }

    case LOAD_PLUGINS_FROM_PATH:
    {
        LOGV("BnDrmManagerService::onTransact :LOAD_PLUGINS_FROM_PATH");
        CHECK_INTERFACE(IDrmManagerService, data, reply);

        status_t status = loadPlugIns(data.readInt32(), data.readString8());

        reply->writeInt32(status);
        return DRM_NO_ERROR;
    }

    case SET_DRM_SERVICE_LISTENER:
    {
        LOGV("BnDrmManagerService::onTransact :SET_DRM_SERVICE_LISTENER");
        CHECK_INTERFACE(IDrmManagerService, data, reply);

        const int uniqueId = data.readInt32();
        const sp<IDrmServiceListener> drmServiceListener
            = interface_cast<IDrmServiceListener> (data.readStrongBinder());

        status_t status = setDrmServiceListener(uniqueId, drmServiceListener);

        reply->writeInt32(status);
        return DRM_NO_ERROR;
    }

    case UNLOAD_PLUGINS:
    {
        LOGV("BnDrmManagerService::onTransact :UNLOAD_PLUGINS");
        CHECK_INTERFACE(IDrmManagerService, data, reply);

        const int uniqueId = data.readInt32();
        status_t status = unloadPlugIns(uniqueId);

        reply->writeInt32(status);
        return DRM_NO_ERROR;
    }

    case INSTALL_DRM_ENGINE:
    {
        LOGV("BnDrmManagerService::onTransact :INSTALL_DRM_ENGINE");
        CHECK_INTERFACE(IDrmManagerService, data, reply);

        status_t status = installDrmEngine(data.readInt32(), data.readString8());

        reply->writeInt32(status);
        return DRM_NO_ERROR;
    }

    case GET_CONSTRAINTS_FROM_CONTENT:
    {
        LOGV("BnDrmManagerService::onTransact :GET_CONSTRAINTS_FROM_CONTENT");
        CHECK_INTERFACE(IDrmManagerService, data, reply);

        const int uniqueId = data.readInt32();
        const String8 path = data.readString8();

        DrmConstraints* drmConstraints = getConstraints(uniqueId, &path, data.readInt32());

        if (NULL != drmConstraints) {
            //Filling DRM Constraints contents
            reply->writeInt32(drmConstraints->getCount());

            DrmConstraints::KeyIterator keyIt = drmConstraints->keyIterator();
            while (keyIt.hasNext()) {
                const String8 key = keyIt.next();
                reply->writeString8(key);
                const char* value = drmConstraints->getAsByteArray(&key);
                int bufferSize = 0;
                if (NULL != value) {
                    bufferSize = strlen(value);
                }
                reply->writeInt32(bufferSize + 1);
                reply->write(value, bufferSize + 1);
            }
        }
        delete drmConstraints; drmConstraints = NULL;
        return DRM_NO_ERROR;
    }

    case CAN_HANDLE:
    {
        LOGV("BnDrmManagerService::onTransact :CAN_HANDLE");
        CHECK_INTERFACE(IDrmManagerService, data, reply);

        const int uniqueId = data.readInt32();
        const String8 path = data.readString8();
        const String8 mimeType = data.readString8();

        bool result = canHandle(uniqueId, path, mimeType);

        reply->writeInt32(result);
        return DRM_NO_ERROR;
    }

    case PROCESS_DRM_INFO:
    {
        LOGV("BnDrmManagerService::onTransact :PROCESS_DRM_INFO");
        CHECK_INTERFACE(IDrmManagerService, data, reply);

        const int uniqueId = data.readInt32();

        //Filling DRM info
        const int infoType = data.readInt32();
        const int bufferSize = data.readInt32();
        char* buffer = NULL;
        if (0 < bufferSize) {
            buffer = (char *)data.readInplace(bufferSize);
        }
        const DrmBuffer drmBuffer(buffer, bufferSize);
        DrmInfo* drmInfo = new DrmInfo(infoType, drmBuffer, data.readString8());

        const int size = data.readInt32();
        for (int index = 0; index < size; ++index) {
            const String8 key(data.readString8());
            const String8 value(data.readString8());
            drmInfo->put(key, (value == String8("NULL")) ? String8("") : value);
        }

        DrmInfoStatus* drmInfoStatus = processDrmInfo(uniqueId, drmInfo);

        if (NULL != drmInfoStatus) {
            //Filling DRM Info Status contents
            reply->writeInt32(drmInfoStatus->statusCode);
            reply->writeString8(drmInfoStatus->mimeType);

            if (NULL != drmInfoStatus->drmBuffer) {
                const DrmBuffer* drmBuffer = drmInfoStatus->drmBuffer;
                const int bufferSize = drmBuffer->length;
                reply->writeInt32(bufferSize);
                if (0 < bufferSize) {
                    reply->write(drmBuffer->data, bufferSize);
                }
                delete [] drmBuffer->data;
                delete drmBuffer; drmBuffer = NULL;
            }
        }
        delete drmInfo; drmInfo = NULL;
        delete drmInfoStatus; drmInfoStatus = NULL;
        return DRM_NO_ERROR;
    }

    case ACQUIRE_DRM_INFO:
    {
        LOGV("BnDrmManagerService::onTransact :ACQUIRE_DRM_INFO");
        CHECK_INTERFACE(IDrmManagerService, data, reply);

        const int uniqueId = data.readInt32();

        //Filling DRM info Request
        DrmInfoRequest* drmInfoRequest = new DrmInfoRequest(data.readInt32(), data.readString8());

        const int size = data.readInt32();
        for (int index = 0; index < size; ++index) {
            const String8 key(data.readString8());
            const String8 value(data.readString8());
            drmInfoRequest->put(key, (value == String8("NULL")) ? String8("") : value);
        }

        DrmInfo* drmInfo = acquireDrmInfo(uniqueId, drmInfoRequest);

        if (NULL != drmInfo) {
            //Filling DRM Info
            const DrmBuffer drmBuffer = drmInfo->getData();
            reply->writeInt32(drmInfo->getInfoType());

            const int bufferSize = drmBuffer.length;
            reply->writeInt32(bufferSize);
            if (0 < bufferSize) {
                reply->write(drmBuffer.data, bufferSize);
            }
            reply->writeString8(drmInfo->getMimeType());
            reply->writeInt32(drmInfo->getCount());

            DrmInfo::KeyIterator keyIt = drmInfo->keyIterator();
            while (keyIt.hasNext()) {
                const String8 key = keyIt.next();
                reply->writeString8(key);
                const String8 value = drmInfo->get(key);
                reply->writeString8((value == String8("")) ? String8("NULL") : value);
            }
            delete [] drmBuffer.data;
        }
        delete drmInfoRequest; drmInfoRequest = NULL;
        delete drmInfo; drmInfo = NULL;
        return DRM_NO_ERROR;
    }

    case SAVE_RIGHTS:
    {
        LOGV("BnDrmManagerService::onTransact :SAVE_RIGHTS");
        CHECK_INTERFACE(IDrmManagerService, data, reply);

        const int uniqueId = data.readInt32();

        //Filling DRM Rights
        const int bufferSize = data.readInt32();
        const DrmBuffer drmBuffer((char *)data.readInplace(bufferSize), bufferSize);

        const String8 mimeType(data.readString8());
        const String8 accountId(data.readString8());
        const String8 subscriptionId(data.readString8());
        const String8 rightsPath(data.readString8());
        const String8 contentPath(data.readString8());

        DrmRights drmRights(drmBuffer,
                            ((mimeType == String8("NULL")) ? String8("") : mimeType),
                            ((accountId == String8("NULL")) ? String8("") : accountId),
                            ((subscriptionId == String8("NULL")) ? String8("") : subscriptionId));

        const status_t status = saveRights(uniqueId, drmRights,
                            ((rightsPath == String8("NULL")) ? String8("") : rightsPath),
                            ((contentPath == String8("NULL")) ? String8("") : contentPath));

        reply->writeInt32(status);
        return DRM_NO_ERROR;
    }

    case GET_ORIGINAL_MIMETYPE:
    {
        LOGV("BnDrmManagerService::onTransact :GET_ORIGINAL_MIMETYPE");
        CHECK_INTERFACE(IDrmManagerService, data, reply);

        const String8 originalMimeType = getOriginalMimeType(data.readInt32(), data.readString8());

        reply->writeString8(originalMimeType);
        return DRM_NO_ERROR;
    }

    case GET_DRM_OBJECT_TYPE:
    {
        LOGV("BnDrmManagerService::onTransact :GET_DRM_OBJECT_TYPE");
        CHECK_INTERFACE(IDrmManagerService, data, reply);

        const int drmObjectType
            = getDrmObjectType(data.readInt32(), data.readString8(), data.readString8());

        reply->writeInt32(drmObjectType);
        return DRM_NO_ERROR;
    }

    case CHECK_RIGHTS_STATUS:
    {
        LOGV("BnDrmManagerService::onTransact :CHECK_RIGHTS_STATUS");
        CHECK_INTERFACE(IDrmManagerService, data, reply);

        const int result
            = checkRightsStatus(data.readInt32(), data.readString8(), data.readInt32());

        reply->writeInt32(result);
        return DRM_NO_ERROR;
    }

    case CONSUME_RIGHTS:
    {
        LOGV("BnDrmManagerService::onTransact :CONSUME_RIGHTS");
        CHECK_INTERFACE(IDrmManagerService, data, reply);

        const int uniqueId = data.readInt32();

        DecryptHandle handle;
        handle.decryptId = data.readInt32();
        handle.mimeType = data.readString8();
        handle.decryptApiType = data.readInt32();
        handle.status = data.readInt32();
        handle.decryptInfo = NULL;

        const int bufferLength = data.readInt32();
        if (INVALID_BUFFER_LENGTH != bufferLength) {
            handle.decryptInfo = new DecryptInfo();
            handle.decryptInfo->decryptBufferLength = bufferLength;
        }

        const status_t status
            = consumeRights(uniqueId, &handle, data.readInt32(),
                static_cast<bool>(data.readInt32()));
        reply->writeInt32(status);

        delete handle.decryptInfo; handle.decryptInfo = NULL;
        return DRM_NO_ERROR;
    }

    case SET_PLAYBACK_STATUS:
    {
        LOGV("BnDrmManagerService::onTransact :SET_PLAYBACK_STATUS");
        CHECK_INTERFACE(IDrmManagerService, data, reply);

        const int uniqueId = data.readInt32();

        DecryptHandle handle;
        handle.decryptId = data.readInt32();
        handle.mimeType = data.readString8();
        handle.decryptApiType = data.readInt32();
        handle.status = data.readInt32();
        handle.decryptInfo = NULL;

        const int bufferLength = data.readInt32();
        if (INVALID_BUFFER_LENGTH != bufferLength) {
            handle.decryptInfo = new DecryptInfo();
            handle.decryptInfo->decryptBufferLength = bufferLength;
        }

        const status_t status
            = setPlaybackStatus(uniqueId, &handle, data.readInt32(), data.readInt32());
        reply->writeInt32(status);

        delete handle.decryptInfo; handle.decryptInfo = NULL;
        return DRM_NO_ERROR;
    }

    case VALIDATE_ACTION:
    {
        LOGV("BnDrmManagerService::onTransact :VALIDATE_ACTION");
        CHECK_INTERFACE(IDrmManagerService, data, reply);

        bool result = validateAction(
                                data.readInt32(),
                                data.readString8(),
                                data.readInt32(),
                                ActionDescription(data.readInt32(), data.readInt32()));

        reply->writeInt32(result);
        return DRM_NO_ERROR;
    }

    case REMOVE_RIGHTS:
    {
        LOGV("BnDrmManagerService::onTransact :REMOVE_RIGHTS");
        CHECK_INTERFACE(IDrmManagerService, data, reply);

        const status_t status = removeRights(data.readInt32(), data.readString8());
        reply->writeInt32(status);

        return DRM_NO_ERROR;
    }

    case REMOVE_ALL_RIGHTS:
    {
        LOGV("BnDrmManagerService::onTransact :REMOVE_ALL_RIGHTS");
        CHECK_INTERFACE(IDrmManagerService, data, reply);

        const status_t status = removeAllRights(data.readInt32());
        reply->writeInt32(status);

        return DRM_NO_ERROR;
    }

    case OPEN_CONVERT_SESSION:
    {
        LOGV("BnDrmManagerService::onTransact :OPEN_CONVERT_SESSION");
        CHECK_INTERFACE(IDrmManagerService, data, reply);

        const int convertId = openConvertSession(data.readInt32(), data.readString8());

        reply->writeInt32(convertId);
        return DRM_NO_ERROR;
    }

    case CONVERT_DATA:
    {
        LOGV("BnDrmManagerService::onTransact :CONVERT_DATA");
        CHECK_INTERFACE(IDrmManagerService, data, reply);

        const int uniqueId = data.readInt32();
        const int convertId = data.readInt32();

        //Filling input data
        const int bufferSize = data.readInt32();
        DrmBuffer* inputData = new DrmBuffer((char *)data.readInplace(bufferSize), bufferSize);

        DrmConvertedStatus*    drmConvertedStatus = convertData(uniqueId, convertId, inputData);

        if (NULL != drmConvertedStatus) {
            //Filling Drm Converted Ststus
            reply->writeInt32(drmConvertedStatus->statusCode);
            reply->writeInt32(drmConvertedStatus->offset);

            if (NULL != drmConvertedStatus->convertedData) {
                const DrmBuffer* convertedData = drmConvertedStatus->convertedData;
                const int bufferSize = convertedData->length;
                reply->writeInt32(bufferSize);
                if (0 < bufferSize) {
                    reply->write(convertedData->data, bufferSize);
                }
                delete [] convertedData->data;
                delete convertedData; convertedData = NULL;
            }
        }
        delete inputData; inputData = NULL;
        delete drmConvertedStatus; drmConvertedStatus = NULL;
        return DRM_NO_ERROR;
    }

    case CLOSE_CONVERT_SESSION:
    {
        LOGV("BnDrmManagerService::onTransact :CLOSE_CONVERT_SESSION");
        CHECK_INTERFACE(IDrmManagerService, data, reply);

        DrmConvertedStatus*    drmConvertedStatus
            = closeConvertSession(data.readInt32(), data.readInt32());

        if (NULL != drmConvertedStatus) {
            //Filling Drm Converted Ststus
            reply->writeInt32(drmConvertedStatus->statusCode);
            reply->writeInt32(drmConvertedStatus->offset);

            if (NULL != drmConvertedStatus->convertedData) {
                const DrmBuffer* convertedData = drmConvertedStatus->convertedData;
                const int bufferSize = convertedData->length;
                reply->writeInt32(bufferSize);
                if (0 < bufferSize) {
                    reply->write(convertedData->data, bufferSize);
                }
                delete [] convertedData->data;
                delete convertedData; convertedData = NULL;
            }
        }
        delete drmConvertedStatus; drmConvertedStatus = NULL;
        return DRM_NO_ERROR;
    }

    case GET_ALL_SUPPORT_INFO:
    {
        LOGV("BnDrmManagerService::onTransact :GET_ALL_SUPPORT_INFO");
        CHECK_INTERFACE(IDrmManagerService, data, reply);

        const int uniqueId = data.readInt32();
        int length = 0;
        DrmSupportInfo* drmSupportInfoArray = NULL;

        status_t status = getAllSupportInfo(uniqueId, &length, &drmSupportInfoArray);

        reply->writeInt32(length);
        for (int i = 0; i < length; ++i) {
            DrmSupportInfo drmSupportInfo = drmSupportInfoArray[i];

            reply->writeInt32(drmSupportInfo.getFileSuffixCount());
            DrmSupportInfo::FileSuffixIterator fileSuffixIt
                = drmSupportInfo.getFileSuffixIterator();
            while (fileSuffixIt.hasNext()) {
                reply->writeString8(fileSuffixIt.next());
            }

            reply->writeInt32(drmSupportInfo.getMimeTypeCount());
            DrmSupportInfo::MimeTypeIterator mimeTypeIt = drmSupportInfo.getMimeTypeIterator();
            while (mimeTypeIt.hasNext()) {
                reply->writeString8(mimeTypeIt.next());
            }
            reply->writeString8(drmSupportInfo.getDescription());
        }
        delete [] drmSupportInfoArray; drmSupportInfoArray = NULL;
        reply->writeInt32(status);
        return DRM_NO_ERROR;
    }

    case OPEN_DECRYPT_SESSION:
    {
        LOGV("BnDrmManagerService::onTransact :OPEN_DECRYPT_SESSION");
        CHECK_INTERFACE(IDrmManagerService, data, reply);

        const int uniqueId = data.readInt32();
        const int fd = data.readFileDescriptor();

        DecryptHandle* handle
            = openDecryptSession(uniqueId, fd, data.readInt32(), data.readInt32());

        if (NULL != handle) {
            reply->writeInt32(handle->decryptId);
            reply->writeString8(handle->mimeType);
            reply->writeInt32(handle->decryptApiType);
            reply->writeInt32(handle->status);
            if (NULL != handle->decryptInfo) {
                reply->writeInt32(handle->decryptInfo->decryptBufferLength);
                delete handle->decryptInfo; handle->decryptInfo = NULL;
            }
        } else {
            LOGE("NULL decryptHandle is returned");
        }
        delete handle; handle = NULL;
        return DRM_NO_ERROR;
    }

    case CLOSE_DECRYPT_SESSION:
    {
        LOGV("BnDrmManagerService::onTransact :CLOSE_DECRYPT_SESSION");
        CHECK_INTERFACE(IDrmManagerService, data, reply);

        const int uniqueId = data.readInt32();

        DecryptHandle* handle = new DecryptHandle();
        handle->decryptId = data.readInt32();
        handle->mimeType = data.readString8();
        handle->decryptApiType = data.readInt32();
        handle->status = data.readInt32();
        handle->decryptInfo = NULL;

        const int bufferLength = data.readInt32();
        if (INVALID_BUFFER_LENGTH != bufferLength) {
            handle->decryptInfo = new DecryptInfo();
            handle->decryptInfo->decryptBufferLength = bufferLength;
        }

        const status_t status = closeDecryptSession(uniqueId, handle);
        reply->writeInt32(status);
        return DRM_NO_ERROR;
    }

    case INITIALIZE_DECRYPT_UNIT:
    {
        LOGV("BnDrmManagerService::onTransact :INITIALIZE_DECRYPT_UNIT");
        CHECK_INTERFACE(IDrmManagerService, data, reply);

        const int uniqueId = data.readInt32();

        DecryptHandle handle;
        handle.decryptId = data.readInt32();
        handle.mimeType = data.readString8();
        handle.decryptApiType = data.readInt32();
        handle.status = data.readInt32();
        handle.decryptInfo = NULL;

        const int bufferLength = data.readInt32();
        if (INVALID_BUFFER_LENGTH != bufferLength) {
            handle.decryptInfo = new DecryptInfo();
            handle.decryptInfo->decryptBufferLength = bufferLength;
        }
        const int decryptUnitId = data.readInt32();

        //Filling Header info
        const int bufferSize = data.readInt32();
        DrmBuffer* headerInfo = NULL;
        headerInfo = new DrmBuffer((char *)data.readInplace(bufferSize), bufferSize);

        const status_t status
            = initializeDecryptUnit(uniqueId, &handle, decryptUnitId, headerInfo);
        reply->writeInt32(status);

        delete handle.decryptInfo; handle.decryptInfo = NULL;
        delete headerInfo; headerInfo = NULL;
        return DRM_NO_ERROR;
    }

    case DECRYPT:
    {
        LOGV("BnDrmManagerService::onTransact :DECRYPT");
        CHECK_INTERFACE(IDrmManagerService, data, reply);

        const int uniqueId = data.readInt32();

        DecryptHandle handle;
        handle.decryptId = data.readInt32();
        handle.mimeType = data.readString8();
        handle.decryptApiType = data.readInt32();
        handle.status = data.readInt32();
        handle.decryptInfo = NULL;

        const int bufferLength = data.readInt32();
        if (INVALID_BUFFER_LENGTH != bufferLength) {
            handle.decryptInfo = new DecryptInfo();
            handle.decryptInfo->decryptBufferLength = bufferLength;
        }
        const int decryptUnitId = data.readInt32();
        const int decBufferSize = data.readInt32();

        const int encBufferSize = data.readInt32();
        DrmBuffer* encBuffer
            = new DrmBuffer((char *)data.readInplace(encBufferSize), encBufferSize);

        char* buffer = NULL;
        buffer = new char[decBufferSize];
        DrmBuffer* decBuffer = new DrmBuffer(buffer, decBufferSize);

        DrmBuffer* IV = NULL;
        if (0 != data.dataAvail()) {
            const int ivBufferlength = data.readInt32();
            IV = new DrmBuffer((char *)data.readInplace(ivBufferlength), ivBufferlength);
        }

        const status_t status
            = decrypt(uniqueId, &handle, decryptUnitId, encBuffer, &decBuffer, IV);

        reply->writeInt32(status);

        const int size = decBuffer->length;
        reply->writeInt32(size);
        reply->write(decBuffer->data, size);

        delete handle.decryptInfo; handle.decryptInfo = NULL;
        delete encBuffer; encBuffer = NULL;
        delete decBuffer; decBuffer = NULL;
        delete [] buffer; buffer = NULL;
        delete IV; IV = NULL;
        return DRM_NO_ERROR;
    }

    case FINALIZE_DECRYPT_UNIT:
    {
        LOGV("BnDrmManagerService::onTransact :FINALIZE_DECRYPT_UNIT");
        CHECK_INTERFACE(IDrmManagerService, data, reply);

        const int uniqueId = data.readInt32();

        DecryptHandle handle;
        handle.decryptId = data.readInt32();
        handle.mimeType = data.readString8();
        handle.decryptApiType = data.readInt32();
        handle.status = data.readInt32();
        handle.decryptInfo = NULL;

        const int bufferLength = data.readInt32();
        if (INVALID_BUFFER_LENGTH != bufferLength) {
            handle.decryptInfo = new DecryptInfo();
            handle.decryptInfo->decryptBufferLength = bufferLength;
        }

        const status_t status = finalizeDecryptUnit(uniqueId, &handle, data.readInt32());
        reply->writeInt32(status);

        delete handle.decryptInfo; handle.decryptInfo = NULL;
        return DRM_NO_ERROR;
    }

    case PREAD:
    {
        LOGV("BnDrmManagerService::onTransact :READ");
        CHECK_INTERFACE(IDrmManagerService, data, reply);

        const int uniqueId = data.readInt32();

        DecryptHandle handle;
        handle.decryptId = data.readInt32();
        handle.mimeType = data.readString8();
        handle.decryptApiType = data.readInt32();
        handle.status = data.readInt32();
        handle.decryptInfo = NULL;

        const int bufferLength = data.readInt32();
        if (INVALID_BUFFER_LENGTH != bufferLength) {
            handle.decryptInfo = new DecryptInfo();
            handle.decryptInfo->decryptBufferLength = bufferLength;
        }

        const int numBytes = data.readInt32();
        char* buffer = new char[numBytes];

        const off_t offset = data.readInt32();

        ssize_t result = pread(uniqueId, &handle, buffer, numBytes, offset);
        reply->writeInt32(result);
        if (0 < result) {
            reply->write(buffer, result);
        }

        delete handle.decryptInfo; handle.decryptInfo = NULL;
        delete [] buffer, buffer = NULL;
        return DRM_NO_ERROR;
    }

    default:
        return BBinder::onTransact(code, data, reply, flags);
    }
}