/*
 * Copyright (C) 2013 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

//#define LOG_NDEBUG 0
#define LOG_TAG "IDrm"
#include <utils/Log.h>

#include <binder/Parcel.h>
#include <media/IDrm.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AString.h>

namespace android {

enum {
    INIT_CHECK = IBinder::FIRST_CALL_TRANSACTION,
    IS_CRYPTO_SUPPORTED,
    CREATE_PLUGIN,
    DESTROY_PLUGIN,
    OPEN_SESSION,
    CLOSE_SESSION,
    GET_KEY_REQUEST,
    PROVIDE_KEY_RESPONSE,
    REMOVE_KEYS,
    RESTORE_KEYS,
    QUERY_KEY_STATUS,
    GET_PROVISION_REQUEST,
    PROVIDE_PROVISION_RESPONSE,
    GET_SECURE_STOPS,
    RELEASE_SECURE_STOPS,
    GET_PROPERTY_STRING,
    GET_PROPERTY_BYTE_ARRAY,
    SET_PROPERTY_STRING,
    SET_PROPERTY_BYTE_ARRAY,
    SET_CIPHER_ALGORITHM,
    SET_MAC_ALGORITHM,
    ENCRYPT,
    DECRYPT,
    SIGN,
    SIGN_RSA,
    VERIFY,
    SET_LISTENER,
    GET_SECURE_STOP,
    RELEASE_ALL_SECURE_STOPS
};

struct BpDrm : public BpInterface<IDrm> {
    explicit BpDrm(const sp<IBinder> &impl)
        : BpInterface<IDrm>(impl) {
    }

    virtual status_t initCheck() const {
        Parcel data, reply;
        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
        status_t status = remote()->transact(INIT_CHECK, data, &reply);
        if (status != OK) {
            return status;
        }

        return reply.readInt32();
    }

    virtual bool isCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType) {
        Parcel data, reply;
        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
        data.write(uuid, 16);
        data.writeString8(mimeType);
        status_t status = remote()->transact(IS_CRYPTO_SUPPORTED, data, &reply);
        if (status != OK) {
            ALOGE("isCryptoSchemeSupported: binder call failed: %d", status);
            return false;
        }

        return reply.readInt32() != 0;
    }

    virtual status_t createPlugin(const uint8_t uuid[16],
                                  const String8& appPackageName) {
        Parcel data, reply;
        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
        data.write(uuid, 16);
        data.writeString8(appPackageName);
        status_t status = remote()->transact(CREATE_PLUGIN, data, &reply);
        if (status != OK) {
            ALOGE("createPlugin: binder call failed: %d", status);
            return status;
        }

        return reply.readInt32();
    }

    virtual status_t destroyPlugin() {
        Parcel data, reply;
        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
        status_t status = remote()->transact(DESTROY_PLUGIN, data, &reply);
        if (status != OK) {
            return status;
        }

        return reply.readInt32();
    }

    virtual status_t openSession(Vector<uint8_t> &sessionId) {
        Parcel data, reply;
        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());

        status_t status = remote()->transact(OPEN_SESSION, data, &reply);
        if (status != OK) {
            return status;
        }
        readVector(reply, sessionId);

        return reply.readInt32();
    }

    virtual status_t closeSession(Vector<uint8_t> const &sessionId) {
        Parcel data, reply;
        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());

        writeVector(data, sessionId);
        status_t status = remote()->transact(CLOSE_SESSION, data, &reply);
        if (status != OK) {
            return status;
        }

        return reply.readInt32();
    }

    virtual status_t
        getKeyRequest(Vector<uint8_t> const &sessionId,
                      Vector<uint8_t> const &initData,
                      String8 const &mimeType, DrmPlugin::KeyType keyType,
                      KeyedVector<String8, String8> const &optionalParameters,
                      Vector<uint8_t> &request, String8 &defaultUrl,
                      DrmPlugin::KeyRequestType *keyRequestType) {
        Parcel data, reply;
        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());

        writeVector(data, sessionId);
        writeVector(data, initData);
        data.writeString8(mimeType);
        data.writeInt32((uint32_t)keyType);

        data.writeInt32(optionalParameters.size());
        for (size_t i = 0; i < optionalParameters.size(); ++i) {
            data.writeString8(optionalParameters.keyAt(i));
            data.writeString8(optionalParameters.valueAt(i));
        }

        status_t status = remote()->transact(GET_KEY_REQUEST, data, &reply);
        if (status != OK) {
            return status;
        }

        readVector(reply, request);
        defaultUrl = reply.readString8();
        *keyRequestType = static_cast<DrmPlugin::KeyRequestType>(reply.readInt32());

        return reply.readInt32();
    }

    virtual status_t provideKeyResponse(Vector<uint8_t> const &sessionId,
                                        Vector<uint8_t> const &response,
                                        Vector<uint8_t> &keySetId) {
        Parcel data, reply;
        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
        writeVector(data, sessionId);
        writeVector(data, response);

        status_t status = remote()->transact(PROVIDE_KEY_RESPONSE, data, &reply);
        if (status != OK) {
            return status;
        }

        readVector(reply, keySetId);

        return reply.readInt32();
    }

    virtual status_t removeKeys(Vector<uint8_t> const &keySetId) {
        Parcel data, reply;
        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());

        writeVector(data, keySetId);
        status_t status = remote()->transact(REMOVE_KEYS, data, &reply);
        if (status != OK) {
            return status;
        }

        return reply.readInt32();
    }

    virtual status_t restoreKeys(Vector<uint8_t> const &sessionId,
                                 Vector<uint8_t> const &keySetId) {
        Parcel data, reply;
        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());

        writeVector(data, sessionId);
        writeVector(data, keySetId);
        status_t status = remote()->transact(RESTORE_KEYS, data, &reply);
        if (status != OK) {
            return status;
        }

        return reply.readInt32();
    }

    virtual status_t queryKeyStatus(Vector<uint8_t> const &sessionId,
                                        KeyedVector<String8, String8> &infoMap) const {
        Parcel data, reply;
        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());

        writeVector(data, sessionId);
        status_t status = remote()->transact(QUERY_KEY_STATUS, data, &reply);
        if (status != OK) {
            return status;
        }

        infoMap.clear();
        size_t count = reply.readInt32();
        for (size_t i = 0; i < count; i++) {
            String8 key = reply.readString8();
            String8 value = reply.readString8();
            infoMap.add(key, value);
        }
        return reply.readInt32();
    }

    virtual status_t getProvisionRequest(String8 const &certType,
                                         String8 const &certAuthority,
                                         Vector<uint8_t> &request,
                                         String8 &defaultUrl) {
        Parcel data, reply;
        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());

        data.writeString8(certType);
        data.writeString8(certAuthority);
        status_t status = remote()->transact(GET_PROVISION_REQUEST, data, &reply);
        if (status != OK) {
            return status;
        }

        readVector(reply, request);
        defaultUrl = reply.readString8();

        return reply.readInt32();
    }

    virtual status_t provideProvisionResponse(Vector<uint8_t> const &response,
                                              Vector<uint8_t> &certificate,
                                              Vector<uint8_t> &wrappedKey) {
        Parcel data, reply;
        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());

        writeVector(data, response);
        status_t status = remote()->transact(PROVIDE_PROVISION_RESPONSE, data, &reply);
        if (status != OK) {
            return status;
        }

        readVector(reply, certificate);
        readVector(reply, wrappedKey);

        return reply.readInt32();
    }

    virtual status_t getSecureStops(List<Vector<uint8_t> > &secureStops) {
        Parcel data, reply;
        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());

        status_t status = remote()->transact(GET_SECURE_STOPS, data, &reply);
        if (status != OK) {
            return status;
        }

        secureStops.clear();
        uint32_t count = reply.readInt32();
        for (size_t i = 0; i < count; i++) {
            Vector<uint8_t> secureStop;
            readVector(reply, secureStop);
            secureStops.push_back(secureStop);
        }
        return reply.readInt32();
    }

    virtual status_t getSecureStop(Vector<uint8_t> const &ssid, Vector<uint8_t> &secureStop) {
        Parcel data, reply;
        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());

        writeVector(data, ssid);
        status_t status = remote()->transact(GET_SECURE_STOP, data, &reply);
        if (status != OK) {
            return status;
        }

        readVector(reply, secureStop);
        return reply.readInt32();
    }

    virtual status_t releaseSecureStops(Vector<uint8_t> const &ssRelease) {
        Parcel data, reply;
        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());

        writeVector(data, ssRelease);
        status_t status = remote()->transact(RELEASE_SECURE_STOPS, data, &reply);
        if (status != OK) {
            return status;
        }

        return reply.readInt32();
    }

    virtual status_t releaseAllSecureStops() {
        Parcel data, reply;
        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());

        status_t status = remote()->transact(RELEASE_ALL_SECURE_STOPS, data, &reply);
        if (status != OK) {
            return status;
        }

        return reply.readInt32();
    }

    virtual status_t getPropertyString(String8 const &name, String8 &value) const {
        Parcel data, reply;
        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());

        data.writeString8(name);
        status_t status = remote()->transact(GET_PROPERTY_STRING, data, &reply);
        if (status != OK) {
            return status;
        }

        value = reply.readString8();
        return reply.readInt32();
    }

    virtual status_t getPropertyByteArray(String8 const &name, Vector<uint8_t> &value) const {
        Parcel data, reply;
        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());

        data.writeString8(name);
        status_t status = remote()->transact(GET_PROPERTY_BYTE_ARRAY, data, &reply);
        if (status != OK) {
            return status;
        }

        readVector(reply, value);
        return reply.readInt32();
    }

    virtual status_t setPropertyString(String8 const &name, String8 const &value) const {
        Parcel data, reply;
        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());

        data.writeString8(name);
        data.writeString8(value);
        status_t status = remote()->transact(SET_PROPERTY_STRING, data, &reply);
        if (status != OK) {
            return status;
        }

        return reply.readInt32();
    }

    virtual status_t setPropertyByteArray(String8 const &name,
                                          Vector<uint8_t> const &value) const {
        Parcel data, reply;
        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());

        data.writeString8(name);
        writeVector(data, value);
        status_t status = remote()->transact(SET_PROPERTY_BYTE_ARRAY, data, &reply);
        if (status != OK) {
            return status;
        }

        return reply.readInt32();
    }


    virtual status_t setCipherAlgorithm(Vector<uint8_t> const &sessionId,
                                        String8 const &algorithm) {
        Parcel data, reply;
        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());

        writeVector(data, sessionId);
        data.writeString8(algorithm);
        status_t status = remote()->transact(SET_CIPHER_ALGORITHM, data, &reply);
        if (status != OK) {
            return status;
        }
        return reply.readInt32();
    }

    virtual status_t setMacAlgorithm(Vector<uint8_t> const &sessionId,
                                     String8 const &algorithm) {
        Parcel data, reply;
        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());

        writeVector(data, sessionId);
        data.writeString8(algorithm);
        status_t status = remote()->transact(SET_MAC_ALGORITHM, data, &reply);
        if (status != OK) {
            return status;
        }
        return reply.readInt32();
    }

    virtual status_t encrypt(Vector<uint8_t> const &sessionId,
                             Vector<uint8_t> const &keyId,
                             Vector<uint8_t> const &input,
                             Vector<uint8_t> const &iv,
                             Vector<uint8_t> &output) {
        Parcel data, reply;
        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());

        writeVector(data, sessionId);
        writeVector(data, keyId);
        writeVector(data, input);
        writeVector(data, iv);

        status_t status = remote()->transact(ENCRYPT, data, &reply);
        if (status != OK) {
            return status;
        }
        readVector(reply, output);

        return reply.readInt32();
    }

    virtual status_t decrypt(Vector<uint8_t> const &sessionId,
                             Vector<uint8_t> const &keyId,
                             Vector<uint8_t> const &input,
                             Vector<uint8_t> const &iv,
                             Vector<uint8_t> &output) {
        Parcel data, reply;
        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());

        writeVector(data, sessionId);
        writeVector(data, keyId);
        writeVector(data, input);
        writeVector(data, iv);

        status_t status = remote()->transact(DECRYPT, data, &reply);
        if (status != OK) {
            return status;
        }
        readVector(reply, output);

        return reply.readInt32();
    }

    virtual status_t sign(Vector<uint8_t> const &sessionId,
                          Vector<uint8_t> const &keyId,
                          Vector<uint8_t> const &message,
                          Vector<uint8_t> &signature) {
        Parcel data, reply;
        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());

        writeVector(data, sessionId);
        writeVector(data, keyId);
        writeVector(data, message);

        status_t status = remote()->transact(SIGN, data, &reply);
        if (status != OK) {
            return status;
        }
        readVector(reply, signature);

        return reply.readInt32();
    }

    virtual status_t verify(Vector<uint8_t> const &sessionId,
                            Vector<uint8_t> const &keyId,
                            Vector<uint8_t> const &message,
                            Vector<uint8_t> const &signature,
                            bool &match) {
        Parcel data, reply;
        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());

        writeVector(data, sessionId);
        writeVector(data, keyId);
        writeVector(data, message);
        writeVector(data, signature);

        status_t status = remote()->transact(VERIFY, data, &reply);
        if (status != OK) {
            return status;
        }
        match = (bool)reply.readInt32();
        return reply.readInt32();
    }

    virtual status_t signRSA(Vector<uint8_t> const &sessionId,
                             String8 const &algorithm,
                             Vector<uint8_t> const &message,
                             Vector<uint8_t> const &wrappedKey,
                             Vector<uint8_t> &signature) {
        Parcel data, reply;
        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());

        writeVector(data, sessionId);
        data.writeString8(algorithm);
        writeVector(data, message);
        writeVector(data, wrappedKey);

        status_t status = remote()->transact(SIGN_RSA, data, &reply);
        if (status != OK) {
            return status;
        }
        readVector(reply, signature);

        return reply.readInt32();
    }

    virtual status_t setListener(const sp<IDrmClient>& listener) {
        Parcel data, reply;
        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
        data.writeStrongBinder(IInterface::asBinder(listener));
        status_t status = remote()->transact(SET_LISTENER, data, &reply);
        if (status != OK) {
            return status;
        }
        return reply.readInt32();
    }

private:
    void readVector(Parcel &reply, Vector<uint8_t> &vector) const {
        uint32_t size = reply.readInt32();
        vector.insertAt((size_t)0, size);
        reply.read(vector.editArray(), size);
    }

    void writeVector(Parcel &data, Vector<uint8_t> const &vector) const {
        data.writeInt32(vector.size());
        data.write(vector.array(), vector.size());
    }

    DISALLOW_EVIL_CONSTRUCTORS(BpDrm);
};

IMPLEMENT_META_INTERFACE(Drm, "android.drm.IDrm");

////////////////////////////////////////////////////////////////////////////////

void BnDrm::readVector(const Parcel &data, Vector<uint8_t> &vector) const {
    uint32_t size = data.readInt32();
    vector.insertAt((size_t)0, size);
    data.read(vector.editArray(), size);
}

void BnDrm::writeVector(Parcel *reply, Vector<uint8_t> const &vector) const {
    reply->writeInt32(vector.size());
    reply->write(vector.array(), vector.size());
}

status_t BnDrm::onTransact(
    uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
    switch (code) {
        case INIT_CHECK:
        {
            CHECK_INTERFACE(IDrm, data, reply);
            reply->writeInt32(initCheck());
            return OK;
        }

        case IS_CRYPTO_SUPPORTED:
        {
            CHECK_INTERFACE(IDrm, data, reply);
            uint8_t uuid[16];
            data.read(uuid, sizeof(uuid));
            String8 mimeType = data.readString8();
            reply->writeInt32(isCryptoSchemeSupported(uuid, mimeType));
            return OK;
        }

        case CREATE_PLUGIN:
        {
            CHECK_INTERFACE(IDrm, data, reply);
            uint8_t uuid[16];
            data.read(uuid, sizeof(uuid));
            String8 appPackageName = data.readString8();
            reply->writeInt32(createPlugin(uuid, appPackageName));
            return OK;
        }

        case DESTROY_PLUGIN:
        {
            CHECK_INTERFACE(IDrm, data, reply);
            reply->writeInt32(destroyPlugin());
            return OK;
        }

        case OPEN_SESSION:
        {
            CHECK_INTERFACE(IDrm, data, reply);
            Vector<uint8_t> sessionId;
            status_t result = openSession(sessionId);
            writeVector(reply, sessionId);
            reply->writeInt32(result);
            return OK;
        }

        case CLOSE_SESSION:
        {
            CHECK_INTERFACE(IDrm, data, reply);
            Vector<uint8_t> sessionId;
            readVector(data, sessionId);
            reply->writeInt32(closeSession(sessionId));
            return OK;
        }

        case GET_KEY_REQUEST:
        {
            CHECK_INTERFACE(IDrm, data, reply);
            Vector<uint8_t> sessionId, initData;

            readVector(data, sessionId);
            readVector(data, initData);
            String8 mimeType = data.readString8();
            DrmPlugin::KeyType keyType = (DrmPlugin::KeyType)data.readInt32();

            KeyedVector<String8, String8> optionalParameters;
            uint32_t count = data.readInt32();
            for (size_t i = 0; i < count; ++i) {
                String8 key, value;
                key = data.readString8();
                value = data.readString8();
                optionalParameters.add(key, value);
            }

            Vector<uint8_t> request;
            String8 defaultUrl;
            DrmPlugin::KeyRequestType keyRequestType = DrmPlugin::kKeyRequestType_Unknown;

            status_t result = getKeyRequest(sessionId, initData, mimeType,
                    keyType, optionalParameters, request, defaultUrl,
                    &keyRequestType);

            writeVector(reply, request);
            reply->writeString8(defaultUrl);
            reply->writeInt32(static_cast<int32_t>(keyRequestType));
            reply->writeInt32(result);
            return OK;
        }

        case PROVIDE_KEY_RESPONSE:
        {
            CHECK_INTERFACE(IDrm, data, reply);
            Vector<uint8_t> sessionId, response, keySetId;
            readVector(data, sessionId);
            readVector(data, response);
            uint32_t result = provideKeyResponse(sessionId, response, keySetId);
            writeVector(reply, keySetId);
            reply->writeInt32(result);
            return OK;
        }

        case REMOVE_KEYS:
        {
            CHECK_INTERFACE(IDrm, data, reply);
            Vector<uint8_t> keySetId;
            readVector(data, keySetId);
            reply->writeInt32(removeKeys(keySetId));
            return OK;
        }

        case RESTORE_KEYS:
        {
            CHECK_INTERFACE(IDrm, data, reply);
            Vector<uint8_t> sessionId, keySetId;
            readVector(data, sessionId);
            readVector(data, keySetId);
            reply->writeInt32(restoreKeys(sessionId, keySetId));
            return OK;
        }

        case QUERY_KEY_STATUS:
        {
            CHECK_INTERFACE(IDrm, data, reply);
            Vector<uint8_t> sessionId;
            readVector(data, sessionId);
            KeyedVector<String8, String8> infoMap;
            status_t result = queryKeyStatus(sessionId, infoMap);
            size_t count = infoMap.size();
            reply->writeInt32(count);
            for (size_t i = 0; i < count; ++i) {
                reply->writeString8(infoMap.keyAt(i));
                reply->writeString8(infoMap.valueAt(i));
            }
            reply->writeInt32(result);
            return OK;
        }

        case GET_PROVISION_REQUEST:
        {
            CHECK_INTERFACE(IDrm, data, reply);
            String8 certType = data.readString8();
            String8 certAuthority = data.readString8();

            Vector<uint8_t> request;
            String8 defaultUrl;
            status_t result = getProvisionRequest(certType, certAuthority,
                                                  request, defaultUrl);
            writeVector(reply, request);
            reply->writeString8(defaultUrl);
            reply->writeInt32(result);
            return OK;
        }

        case PROVIDE_PROVISION_RESPONSE:
        {
            CHECK_INTERFACE(IDrm, data, reply);
            Vector<uint8_t> response;
            Vector<uint8_t> certificate;
            Vector<uint8_t> wrappedKey;
            readVector(data, response);
            status_t result = provideProvisionResponse(response, certificate, wrappedKey);
            writeVector(reply, certificate);
            writeVector(reply, wrappedKey);
            reply->writeInt32(result);
            return OK;
        }

        case GET_SECURE_STOPS:
        {
            CHECK_INTERFACE(IDrm, data, reply);
            List<Vector<uint8_t> > secureStops;
            status_t result = getSecureStops(secureStops);
            size_t count = secureStops.size();
            reply->writeInt32(count);
            List<Vector<uint8_t> >::iterator iter = secureStops.begin();
            while(iter != secureStops.end()) {
                size_t size = iter->size();
                reply->writeInt32(size);
                reply->write(iter->array(), iter->size());
                iter++;
            }
            reply->writeInt32(result);
            return OK;
        }

        case GET_SECURE_STOP:
        {
            CHECK_INTERFACE(IDrm, data, reply);
            Vector<uint8_t> ssid, secureStop;
            readVector(data, ssid);
            status_t result = getSecureStop(ssid, secureStop);
            writeVector(reply, secureStop);
            reply->writeInt32(result);
            return OK;
        }

        case RELEASE_SECURE_STOPS:
        {
            CHECK_INTERFACE(IDrm, data, reply);
            Vector<uint8_t> ssRelease;
            readVector(data, ssRelease);
            reply->writeInt32(releaseSecureStops(ssRelease));
            return OK;
        }

        case RELEASE_ALL_SECURE_STOPS:
        {
            CHECK_INTERFACE(IDrm, data, reply);
            reply->writeInt32(releaseAllSecureStops());
            return OK;
        }

        case GET_PROPERTY_STRING:
        {
            CHECK_INTERFACE(IDrm, data, reply);
            String8 name = data.readString8();
            String8 value;
            status_t result = getPropertyString(name, value);
            reply->writeString8(value);
            reply->writeInt32(result);
            return OK;
        }

        case GET_PROPERTY_BYTE_ARRAY:
        {
            CHECK_INTERFACE(IDrm, data, reply);
            String8 name = data.readString8();
            Vector<uint8_t> value;
            status_t result = getPropertyByteArray(name, value);
            writeVector(reply, value);
            reply->writeInt32(result);
            return OK;
        }

        case SET_PROPERTY_STRING:
        {
            CHECK_INTERFACE(IDrm, data, reply);
            String8 name = data.readString8();
            String8 value = data.readString8();
            reply->writeInt32(setPropertyString(name, value));
            return OK;
        }

        case SET_PROPERTY_BYTE_ARRAY:
        {
            CHECK_INTERFACE(IDrm, data, reply);
            String8 name = data.readString8();
            Vector<uint8_t> value;
            readVector(data, value);
            reply->writeInt32(setPropertyByteArray(name, value));
            return OK;
        }

        case SET_CIPHER_ALGORITHM:
        {
            CHECK_INTERFACE(IDrm, data, reply);
            Vector<uint8_t> sessionId;
            readVector(data, sessionId);
            String8 algorithm = data.readString8();
            reply->writeInt32(setCipherAlgorithm(sessionId, algorithm));
            return OK;
        }

        case SET_MAC_ALGORITHM:
        {
            CHECK_INTERFACE(IDrm, data, reply);
            Vector<uint8_t> sessionId;
            readVector(data, sessionId);
            String8 algorithm = data.readString8();
            reply->writeInt32(setMacAlgorithm(sessionId, algorithm));
            return OK;
        }

        case ENCRYPT:
        {
            CHECK_INTERFACE(IDrm, data, reply);
            Vector<uint8_t> sessionId, keyId, input, iv, output;
            readVector(data, sessionId);
            readVector(data, keyId);
            readVector(data, input);
            readVector(data, iv);
            uint32_t result = encrypt(sessionId, keyId, input, iv, output);
            writeVector(reply, output);
            reply->writeInt32(result);
            return OK;
        }

        case DECRYPT:
        {
            CHECK_INTERFACE(IDrm, data, reply);
            Vector<uint8_t> sessionId, keyId, input, iv, output;
            readVector(data, sessionId);
            readVector(data, keyId);
            readVector(data, input);
            readVector(data, iv);
            uint32_t result = decrypt(sessionId, keyId, input, iv, output);
            writeVector(reply, output);
            reply->writeInt32(result);
            return OK;
        }

        case SIGN:
        {
            CHECK_INTERFACE(IDrm, data, reply);
            Vector<uint8_t> sessionId, keyId, message, signature;
            readVector(data, sessionId);
            readVector(data, keyId);
            readVector(data, message);
            uint32_t result = sign(sessionId, keyId, message, signature);
            writeVector(reply, signature);
            reply->writeInt32(result);
            return OK;
        }

        case VERIFY:
        {
            CHECK_INTERFACE(IDrm, data, reply);
            Vector<uint8_t> sessionId, keyId, message, signature;
            readVector(data, sessionId);
            readVector(data, keyId);
            readVector(data, message);
            readVector(data, signature);
            bool match = false;
            uint32_t result = verify(sessionId, keyId, message, signature, match);
            reply->writeInt32(match);
            reply->writeInt32(result);
            return OK;
        }

        case SIGN_RSA:
        {
            CHECK_INTERFACE(IDrm, data, reply);
            Vector<uint8_t> sessionId, message, wrappedKey, signature;
            readVector(data, sessionId);
            String8 algorithm = data.readString8();
            readVector(data, message);
            readVector(data, wrappedKey);
            uint32_t result = signRSA(sessionId, algorithm, message, wrappedKey, signature);
            writeVector(reply, signature);
            reply->writeInt32(result);
            return OK;
        }

    case SET_LISTENER: {
        CHECK_INTERFACE(IDrm, data, reply);
        sp<IDrmClient> listener =
            interface_cast<IDrmClient>(data.readStrongBinder());
        reply->writeInt32(setListener(listener));
        return NO_ERROR;
    } break;

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

}  // namespace android
