/*
**
** Copyright 2008, 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.
*/

#include <stdint.h>
#include <sys/limits.h>
#include <sys/types.h>

#include <algorithm>
#include <limits>

#define LOG_TAG "KeystoreService"
#include <utils/Log.h>

#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/Parcel.h>

#include <keystore/IKeystoreService.h>
#include <keystore/keystore_hidl_support.h>

#include "keystore_aidl_hidl_marshalling_utils.h"

namespace android {
using namespace ::keystore;

const ssize_t MAX_GENERATE_ARGS = 3;

KeystoreArg::KeystoreArg(const void* data, size_t len) : mData(data), mSize(len) {}

KeystoreArg::~KeystoreArg() {}

const void* KeystoreArg::data() const {
    return mData;
}

size_t KeystoreArg::size() const {
    return mSize;
}

OperationResult::OperationResult() : resultCode(), token(), handle(0), inputConsumed(0), data() {}

OperationResult::~OperationResult() {}

status_t OperationResult::readFromParcel(const Parcel* inn) {
    const Parcel& in = *inn;
    resultCode = ErrorCode(in.readInt32());
    token = in.readStrongBinder();
    handle = static_cast<uint64_t>(in.readInt64());
    inputConsumed = in.readInt32();
    data = readKeymasterBlob(in);
    outParams = readParamSetFromParcel(in);
    return OK;
}

status_t OperationResult::writeToParcel(Parcel* out) const {
    out->writeInt32(resultCode);
    out->writeStrongBinder(token);
    out->writeInt64(handle);
    out->writeInt32(inputConsumed);
    writeKeymasterBlob(data, out);
    writeParamSetToParcel(outParams, out);
    return OK;
}

ExportResult::ExportResult() : resultCode() {}

ExportResult::~ExportResult() {}

status_t ExportResult::readFromParcel(const Parcel* inn) {
    const Parcel& in = *inn;
    resultCode = ErrorCode(in.readInt32());
    exportData = readKeymasterBlob(in);
    return OK;
}

status_t ExportResult::writeToParcel(Parcel* out) const {
    out->writeInt32(resultCode);
    writeKeymasterBlob(exportData, out);
    return OK;
}

/**
 * Read a byte array from in. The data at *data is still owned by the parcel
 */
static void readByteArray(const Parcel& in, const uint8_t** data, size_t* length) {
    ssize_t slength = in.readInt32();
    if (slength > 0) {
        *data = reinterpret_cast<const uint8_t*>(in.readInplace(slength));
        if (*data) {
            *length = static_cast<size_t>(slength);
        } else {
            *length = 0;
        }
    } else {
        *data = NULL;
        *length = 0;
    }
}

class BpKeystoreService : public BpInterface<IKeystoreService> {
  public:
    explicit BpKeystoreService(const sp<IBinder>& impl) : BpInterface<IKeystoreService>(impl) {}

    // test ping
    KeyStoreServiceReturnCode getState(int32_t userId) override {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeInt32(userId);
        status_t status = remote()->transact(BnKeystoreService::GET_STATE, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("getState() could not contact remote: %d\n", status);
            return ResponseCode::SYSTEM_ERROR;
        }
        int32_t err = reply.readExceptionCode();
        ResponseCode ret = ResponseCode(reply.readInt32());
        if (err < 0) {
            ALOGD("getState() caught exception %d\n", err);
            return ResponseCode::SYSTEM_ERROR;
        }
        return ret;
    }

    KeyStoreServiceReturnCode get(const String16& name, int32_t uid,
                                  hidl_vec<uint8_t>* item) override {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeString16(name);
        data.writeInt32(uid);
        status_t status = remote()->transact(BnKeystoreService::GET, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("get() could not contact remote: %d\n", status);
            return ResponseCode::SYSTEM_ERROR;
        }
        int32_t err = reply.readExceptionCode();
        if (err < 0) {
            ALOGD("get() caught exception %d\n", err);
            return ResponseCode::SYSTEM_ERROR;
        }
        auto resultItem = readBlobAsByteArray(reply);
        if (item) *item = resultItem.value();
        return ResponseCode(reply.readInt32());
    }

    KeyStoreServiceReturnCode insert(const String16& name, const hidl_vec<uint8_t>& item, int uid,
                                     int32_t flags) override {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeString16(name);
        writeBlobAsByteArray(item, &data);
        data.writeInt32(uid);
        data.writeInt32(flags);
        status_t status = remote()->transact(BnKeystoreService::INSERT, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("import() could not contact remote: %d\n", status);
            return ResponseCode::SYSTEM_ERROR;
        }
        int32_t err = reply.readExceptionCode();
        if (err < 0) {
            ALOGD("import() caught exception %d\n", err);
            return ResponseCode::SYSTEM_ERROR;
        }
        return ResponseCode(reply.readInt32());
    }

    KeyStoreServiceReturnCode del(const String16& name, int uid) override {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeString16(name);
        data.writeInt32(uid);
        status_t status = remote()->transact(BnKeystoreService::DEL, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("del() could not contact remote: %d\n", status);
            return ResponseCode::SYSTEM_ERROR;
        }
        int32_t err = reply.readExceptionCode();
        if (err < 0) {
            ALOGD("del() caught exception %d\n", err);
            return ResponseCode::SYSTEM_ERROR;
        }
        return ResponseCode(reply.readInt32());
    }

    KeyStoreServiceReturnCode exist(const String16& name, int uid) override {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeString16(name);
        data.writeInt32(uid);
        status_t status = remote()->transact(BnKeystoreService::EXIST, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("exist() could not contact remote: %d\n", status);
            return ResponseCode::SYSTEM_ERROR;
        }
        int32_t err = reply.readExceptionCode();
        if (err < 0) {
            ALOGD("exist() caught exception %d\n", err);
            return ResponseCode::SYSTEM_ERROR;
        }
        return ResponseCode(reply.readInt32());
    }

    KeyStoreServiceReturnCode list(const String16& prefix, int uid,
                                   Vector<String16>* matches) override {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeString16(prefix);
        data.writeInt32(uid);
        status_t status = remote()->transact(BnKeystoreService::LIST, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("list() could not contact remote: %d\n", status);
            return ResponseCode::SYSTEM_ERROR;
        }
        int32_t err = reply.readExceptionCode();
        int32_t numMatches = reply.readInt32();
        for (int32_t i = 0; i < numMatches; i++) {
            matches->push(reply.readString16());
        }
        if (err < 0) {
            ALOGD("list() caught exception %d\n", err);
            return ResponseCode::SYSTEM_ERROR;
        }
        return ResponseCode(reply.readInt32());
    }

    KeyStoreServiceReturnCode reset() override {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        status_t status = remote()->transact(BnKeystoreService::RESET, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("reset() could not contact remote: %d\n", status);
            return ResponseCode::SYSTEM_ERROR;
        }
        int32_t err = reply.readExceptionCode();
        if (err < 0) {
            ALOGD("reset() caught exception %d\n", err);
            return ResponseCode::SYSTEM_ERROR;
        }
        return ResponseCode(reply.readInt32());
    }

    KeyStoreServiceReturnCode onUserPasswordChanged(int32_t userId,
                                                    const String16& password) override {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeInt32(userId);
        data.writeString16(password);
        status_t status =
            remote()->transact(BnKeystoreService::ON_USER_PASSWORD_CHANGED, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("onUserPasswordChanged() could not contact remote: %d\n", status);
            return ResponseCode::SYSTEM_ERROR;
        }
        int32_t err = reply.readExceptionCode();
        if (err < 0) {
            ALOGD("onUserPasswordChanged() caught exception %d\n", err);
            return ResponseCode::SYSTEM_ERROR;
        }
        return ResponseCode(reply.readInt32());
    }

    KeyStoreServiceReturnCode lock(int32_t userId) override {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeInt32(userId);
        status_t status = remote()->transact(BnKeystoreService::LOCK, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("lock() could not contact remote: %d\n", status);
            return ResponseCode::SYSTEM_ERROR;
        }
        int32_t err = reply.readExceptionCode();
        if (err < 0) {
            ALOGD("lock() caught exception %d\n", err);
            return ResponseCode::SYSTEM_ERROR;
        }
        return ResponseCode(reply.readInt32());
    }

    KeyStoreServiceReturnCode unlock(int32_t userId, const String16& password) override {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeInt32(userId);
        data.writeString16(password);
        status_t status = remote()->transact(BnKeystoreService::UNLOCK, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("unlock() could not contact remote: %d\n", status);
            return ResponseCode::SYSTEM_ERROR;
        }
        int32_t err = reply.readExceptionCode();
        if (err < 0) {
            ALOGD("unlock() caught exception %d\n", err);
            return ResponseCode::SYSTEM_ERROR;
        }
        return ResponseCode(reply.readInt32());
    }

    bool isEmpty(int32_t userId) override {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeInt32(userId);
        status_t status = remote()->transact(BnKeystoreService::IS_EMPTY, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("isEmpty() could not contact remote: %d\n", status);
            return false;
        }
        int32_t err = reply.readExceptionCode();
        if (err < 0) {
            ALOGD("isEmpty() caught exception %d\n", err);
            return false;
        }
        return reply.readInt32() != 0;
    }

    KeyStoreServiceReturnCode generate(const String16& name, int32_t uid, int32_t keyType,
                                       int32_t keySize, int32_t flags,
                                       Vector<sp<KeystoreArg>>* args) override {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeString16(name);
        data.writeInt32(uid);
        data.writeInt32(keyType);
        data.writeInt32(keySize);
        data.writeInt32(flags);
        data.writeInt32(1);
        data.writeInt32(args->size());
        for (Vector<sp<KeystoreArg>>::iterator it = args->begin(); it != args->end(); ++it) {
            sp<KeystoreArg> item = *it;
            size_t keyLength = item->size();
            data.writeInt32(keyLength);
            void* buf = data.writeInplace(keyLength);
            memcpy(buf, item->data(), keyLength);
        }
        status_t status = remote()->transact(BnKeystoreService::GENERATE, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("generate() could not contact remote: %d\n", status);
            return ResponseCode::SYSTEM_ERROR;
        }
        int32_t err = reply.readExceptionCode();
        if (err < 0) {
            ALOGD("generate() caught exception %d\n", err);
            return ResponseCode::SYSTEM_ERROR;
        }
        return ResponseCode(reply.readInt32());
    }

    KeyStoreServiceReturnCode import(const String16& name, const hidl_vec<uint8_t>& key, int uid,
                                     int flags) override {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeString16(name);
        writeBlobAsByteArray(key, &data);
        data.writeInt32(uid);
        data.writeInt32(flags);
        status_t status = remote()->transact(BnKeystoreService::IMPORT, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("import() could not contact remote: %d\n", status);
            return ResponseCode::SYSTEM_ERROR;
        }
        int32_t err = reply.readExceptionCode();
        if (err < 0) {
            ALOGD("import() caught exception %d\n", err);
            return ResponseCode::SYSTEM_ERROR;
        }
        return ResponseCode(reply.readInt32());
    }

    KeyStoreServiceReturnCode sign(const String16& name, const hidl_vec<uint8_t>& in,
                                   hidl_vec<uint8_t>* out) override {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeString16(name);
        writeBlobAsByteArray(in, &data);
        status_t status = remote()->transact(BnKeystoreService::SIGN, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("import() could not contact remote: %d\n", status);
            return ResponseCode::SYSTEM_ERROR;
        }
        int32_t err = reply.readExceptionCode();
        if (err < 0) {
            ALOGD("import() caught exception %d\n", err);
            return ResponseCode::SYSTEM_ERROR;
        }
        auto outBlob = readBlobAsByteArray(reply);
        if (out) {
            // don't need to check outBlob.isOk()
            // if !outBlob.isOk() the wrapped value is default constructed and therefore empty,
            // as expected.
            *out = outBlob.value();
        }
        return ResponseCode(reply.readInt32());
    }

    KeyStoreServiceReturnCode verify(const String16& name, const hidl_vec<uint8_t>& in,
                                     const hidl_vec<uint8_t>& signature) override {
        Parcel data, reply;

        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeString16(name);
        writeBlobAsByteArray(in, &data);
        writeBlobAsByteArray(signature, &data);
        status_t status = remote()->transact(BnKeystoreService::VERIFY, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("verify() could not contact remote: %d\n", status);
            return ResponseCode::SYSTEM_ERROR;
        }
        int32_t err = reply.readExceptionCode();
        if (err < 0) {
            ALOGD("verify() caught exception %d\n", err);
            return ResponseCode::SYSTEM_ERROR;
        }
        return ResponseCode(reply.readInt32());
    }

    KeyStoreServiceReturnCode get_pubkey(const String16& name, hidl_vec<uint8_t>* pubkey) override {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeString16(name);
        status_t status = remote()->transact(BnKeystoreService::GET_PUBKEY, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("get_pubkey() could not contact remote: %d\n", status);
            return ResponseCode::SYSTEM_ERROR;
        }
        int32_t err = reply.readExceptionCode();
        if (err < 0) {
            ALOGD("get_pubkey() caught exception %d\n", err);
            return ResponseCode::SYSTEM_ERROR;
        }
        auto resultKey = readBlobAsByteArray(reply);
        if (pubkey) *pubkey = resultKey.value();
        return ResponseCode(reply.readInt32());
    }

    KeyStoreServiceReturnCode grant(const String16& name, int32_t granteeUid) override {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeString16(name);
        data.writeInt32(granteeUid);
        status_t status = remote()->transact(BnKeystoreService::GRANT, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("grant() could not contact remote: %d\n", status);
            return ResponseCode::SYSTEM_ERROR;
        }
        int32_t err = reply.readExceptionCode();
        if (err < 0) {
            ALOGD("grant() caught exception %d\n", err);
            return ResponseCode::SYSTEM_ERROR;
        }
        return ResponseCode(reply.readInt32());
    }

    KeyStoreServiceReturnCode ungrant(const String16& name, int32_t granteeUid) override {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeString16(name);
        data.writeInt32(granteeUid);
        status_t status = remote()->transact(BnKeystoreService::UNGRANT, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("ungrant() could not contact remote: %d\n", status);
            return ResponseCode::SYSTEM_ERROR;
        }
        int32_t err = reply.readExceptionCode();
        if (err < 0) {
            ALOGD("ungrant() caught exception %d\n", err);
            return ResponseCode::SYSTEM_ERROR;
        }
        return ResponseCode(reply.readInt32());
    }

    int64_t getmtime(const String16& name, int32_t uid) override {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeString16(name);
        data.writeInt32(uid);
        status_t status = remote()->transact(BnKeystoreService::GETMTIME, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("getmtime() could not contact remote: %d\n", status);
            return -1;
        }
        int32_t err = reply.readExceptionCode();
        if (err < 0) {
            ALOGD("getmtime() caught exception %d\n", err);
            return -1;
        }
        return reply.readInt64();
    }

    KeyStoreServiceReturnCode duplicate(const String16& srcKey, int32_t srcUid,
                                        const String16& destKey, int32_t destUid) override {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeString16(srcKey);
        data.writeInt32(srcUid);
        data.writeString16(destKey);
        data.writeInt32(destUid);
        status_t status = remote()->transact(BnKeystoreService::DUPLICATE, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("duplicate() could not contact remote: %d\n", status);
            return ResponseCode::SYSTEM_ERROR;
        }
        int32_t err = reply.readExceptionCode();
        if (err < 0) {
            ALOGD("duplicate() caught exception %d\n", err);
            return ResponseCode::SYSTEM_ERROR;
        }
        return ResponseCode(reply.readInt32());
    }

    int32_t is_hardware_backed(const String16& keyType) override {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeString16(keyType);
        status_t status = remote()->transact(BnKeystoreService::IS_HARDWARE_BACKED, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("is_hardware_backed() could not contact remote: %d\n", status);
            return -1;
        }
        int32_t err = reply.readExceptionCode();
        if (err < 0) {
            ALOGD("is_hardware_backed() caught exception %d\n", err);
            return -1;
        }
        return reply.readInt32();
    }

    KeyStoreServiceReturnCode clear_uid(int64_t uid) override {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeInt64(uid);
        status_t status = remote()->transact(BnKeystoreService::CLEAR_UID, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("clear_uid() could not contact remote: %d\n", status);
            return ResponseCode::SYSTEM_ERROR;
        }
        int32_t err = reply.readExceptionCode();
        if (err < 0) {
            ALOGD("clear_uid() caught exception %d\n", err);
            return ResponseCode::SYSTEM_ERROR;
        }
        return ResponseCode(reply.readInt32());
    }

    KeyStoreServiceReturnCode addRngEntropy(const hidl_vec<uint8_t>& entropy) override {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        writeBlobAsByteArray(entropy, &data);
        status_t status = remote()->transact(BnKeystoreService::ADD_RNG_ENTROPY, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("addRngEntropy() could not contact remote: %d\n", status);
            return ResponseCode::SYSTEM_ERROR;
        }
        int32_t err = reply.readExceptionCode();
        if (err < 0) {
            ALOGD("addRngEntropy() caught exception %d\n", err);
            return ResponseCode::SYSTEM_ERROR;
        }
        return ResponseCode(reply.readInt32());
    };

    KeyStoreServiceReturnCode generateKey(const String16& name,
                                          const hidl_vec<KeyParameter>& params,
                                          const hidl_vec<uint8_t>& entropy, int uid, int flags,
                                          KeyCharacteristics* outCharacteristics) override {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeString16(name);
        nullable(writeParamSetToParcel, params, &data);
        writeBlobAsByteArray(entropy, &data);
        data.writeInt32(uid);
        data.writeInt32(flags);
        status_t status = remote()->transact(BnKeystoreService::GENERATE_KEY, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("generateKey() could not contact remote: %d\n", status);
            return ResponseCode::SYSTEM_ERROR;
        }
        int32_t err = reply.readExceptionCode();
        ResponseCode ret = ResponseCode(reply.readInt32());
        if (err < 0) {
            ALOGD("generateKey() caught exception %d\n", err);
            return ResponseCode::SYSTEM_ERROR;
        }
        if (outCharacteristics) {
            *outCharacteristics = nullable(readKeyCharacteristicsFromParcel, reply).value();
        }
        return ret;
    }
    KeyStoreServiceReturnCode
    getKeyCharacteristics(const String16& name, const hidl_vec<uint8_t>& clientId,
                          const hidl_vec<uint8_t>& appData, int32_t uid,
                          KeyCharacteristics* outCharacteristics) override {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeString16(name);
        writeBlobAsByteArray(clientId, &data);
        writeBlobAsByteArray(appData, &data);
        data.writeInt32(uid);
        status_t status =
            remote()->transact(BnKeystoreService::GET_KEY_CHARACTERISTICS, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("getKeyCharacteristics() could not contact remote: %d\n", status);
            return ResponseCode::SYSTEM_ERROR;
        }
        int32_t err = reply.readExceptionCode();
        ResponseCode ret = ResponseCode(reply.readInt32());
        if (err < 0) {
            ALOGD("getKeyCharacteristics() caught exception %d\n", err);
            return ResponseCode::SYSTEM_ERROR;
        }
        if (outCharacteristics) {
            *outCharacteristics = nullable(readKeyCharacteristicsFromParcel, reply).value();
        }
        return ret;
    }
    KeyStoreServiceReturnCode importKey(const String16& name, const hidl_vec<KeyParameter>& params,
                                        KeyFormat format, const hidl_vec<uint8_t>& keyData, int uid,
                                        int flags,
                                        KeyCharacteristics* outCharacteristics) override {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeString16(name);
        nullable(writeParamSetToParcel, params, &data);
        data.writeInt32(uint32_t(format));
        writeBlobAsByteArray(keyData, &data);
        data.writeInt32(uid);
        data.writeInt32(flags);
        status_t status = remote()->transact(BnKeystoreService::IMPORT_KEY, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("importKey() could not contact remote: %d\n", status);
            return ResponseCode::SYSTEM_ERROR;
        }
        int32_t err = reply.readExceptionCode();
        ResponseCode ret = ResponseCode(reply.readInt32());
        if (err < 0) {
            ALOGD("importKey() caught exception %d\n", err);
            return ResponseCode::SYSTEM_ERROR;
        }
        if (outCharacteristics) {
            *outCharacteristics = nullable(readKeyCharacteristicsFromParcel, reply).value();
        }
        return ret;
    }

    void exportKey(const String16& name, KeyFormat format, const hidl_vec<uint8_t>& clientId,
                   const hidl_vec<uint8_t>& appData, int32_t uid, ExportResult* result) override {
        if (!result) {
            return;
        }

        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeString16(name);
        data.writeInt32(int32_t(format));
        writeBlobAsByteArray(clientId, &data);
        writeBlobAsByteArray(appData, &data);
        data.writeInt32(uid);
        status_t status = remote()->transact(BnKeystoreService::EXPORT_KEY, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("exportKey() could not contact remote: %d\n", status);
            result->resultCode = ResponseCode::SYSTEM_ERROR;
            return;
        }
        int32_t err = reply.readExceptionCode();
        if (err < 0) {
            ALOGD("exportKey() caught exception %d\n", err);
            result->resultCode = ResponseCode::SYSTEM_ERROR;
            return;
        }

        reply.readParcelable(result);
    }

    void begin(const sp<IBinder>& appToken, const String16& name, KeyPurpose purpose,
               bool pruneable, const hidl_vec<KeyParameter>& params,
               const hidl_vec<uint8_t>& entropy, int32_t uid, OperationResult* result) override {
        if (!result) {
            return;
        }
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeStrongBinder(appToken);
        data.writeString16(name);
        data.writeInt32(int32_t(purpose));
        data.writeInt32(pruneable ? 1 : 0);
        nullable(writeParamSetToParcel, params, &data);
        writeBlobAsByteArray(entropy, &data);
        data.writeInt32(uid);
        status_t status = remote()->transact(BnKeystoreService::BEGIN, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("begin() could not contact remote: %d\n", status);
            result->resultCode = ResponseCode::SYSTEM_ERROR;
            return;
        }
        int32_t err = reply.readExceptionCode();
        if (err < 0) {
            ALOGD("begin() caught exception %d\n", err);
            result->resultCode = ResponseCode::SYSTEM_ERROR;
            return;
        }

        reply.readParcelable(result);
    }

    void update(const sp<IBinder>& token, const hidl_vec<KeyParameter>& params,
                const hidl_vec<uint8_t>& opData, OperationResult* result) override {
        if (!result) {
            return;
        }
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeStrongBinder(token);
        nullable(writeParamSetToParcel, params, &data);
        writeBlobAsByteArray(opData, &data);
        status_t status = remote()->transact(BnKeystoreService::UPDATE, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("update() could not contact remote: %d\n", status);
            result->resultCode = ResponseCode::SYSTEM_ERROR;
            return;
        }
        int32_t err = reply.readExceptionCode();
        if (err < 0) {
            ALOGD("update() caught exception %d\n", err);
            result->resultCode = ResponseCode::SYSTEM_ERROR;
            return;
        }

        reply.readParcelable(result);
    }

    void finish(const sp<IBinder>& token, const hidl_vec<KeyParameter>& params,
                const hidl_vec<uint8_t>& signature, const hidl_vec<uint8_t>& entropy,
                OperationResult* result) override {
        if (!result) {
            return;
        }
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeStrongBinder(token);
        nullable(writeParamSetToParcel, params, &data);
        writeBlobAsByteArray(signature, &data);
        writeBlobAsByteArray(entropy, &data);
        status_t status = remote()->transact(BnKeystoreService::FINISH, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("finish() could not contact remote: %d\n", status);
            result->resultCode = ResponseCode::SYSTEM_ERROR;
            return;
        }
        int32_t err = reply.readExceptionCode();
        if (err < 0) {
            ALOGD("finish() caught exception %d\n", err);
            result->resultCode = ResponseCode::SYSTEM_ERROR;
            return;
        }

        reply.readParcelable(result);
    }

    KeyStoreServiceReturnCode abort(const sp<IBinder>& token) override {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeStrongBinder(token);
        status_t status = remote()->transact(BnKeystoreService::ABORT, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("abort() could not contact remote: %d\n", status);
            return ResponseCode::SYSTEM_ERROR;
        }
        int32_t err = reply.readExceptionCode();
        if (err < 0) {
            ALOGD("abort() caught exception %d\n", err);
            return ResponseCode::SYSTEM_ERROR;
        }
        return ResponseCode(reply.readInt32());
    }

    bool isOperationAuthorized(const sp<IBinder>& token) override {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeStrongBinder(token);
        status_t status =
            remote()->transact(BnKeystoreService::IS_OPERATION_AUTHORIZED, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("isOperationAuthorized() could not contact remote: %d\n", status);
            return false;
        }
        int32_t err = reply.readExceptionCode();
        if (err < 0) {
            ALOGD("isOperationAuthorized() caught exception %d\n", err);
            return false;
        }
        return reply.readInt32() == 1;
    }

    KeyStoreServiceReturnCode addAuthToken(const uint8_t* token, size_t length) override {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeByteArray(length, token);
        status_t status = remote()->transact(BnKeystoreService::ADD_AUTH_TOKEN, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("addAuthToken() could not contact remote: %d\n", status);
            return ResponseCode::SYSTEM_ERROR;
        }
        int32_t err = reply.readExceptionCode();
        if (err < 0) {
            ALOGD("addAuthToken() caught exception %d\n", err);
            return ResponseCode::SYSTEM_ERROR;
        }
        return ResponseCode(reply.readInt32());
    };

    KeyStoreServiceReturnCode onUserAdded(int32_t userId, int32_t parentId) override {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeInt32(userId);
        data.writeInt32(parentId);
        status_t status = remote()->transact(BnKeystoreService::ON_USER_ADDED, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("onUserAdded() could not contact remote: %d\n", status);
            return ResponseCode::SYSTEM_ERROR;
        }
        int32_t err = reply.readExceptionCode();
        if (err < 0) {
            ALOGD("onUserAdded() caught exception %d\n", err);
            return ResponseCode::SYSTEM_ERROR;
        }
        return ResponseCode(reply.readInt32());
    }

    KeyStoreServiceReturnCode onUserRemoved(int32_t userId) override {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeInt32(userId);
        status_t status = remote()->transact(BnKeystoreService::ON_USER_REMOVED, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("onUserRemoved() could not contact remote: %d\n", status);
            return ResponseCode::SYSTEM_ERROR;
        }
        int32_t err = reply.readExceptionCode();
        if (err < 0) {
            ALOGD("onUserRemoved() caught exception %d\n", err);
            return ResponseCode::SYSTEM_ERROR;
        }
        return ResponseCode(reply.readInt32());
    }

    KeyStoreServiceReturnCode attestKey(const String16& name, const hidl_vec<KeyParameter>& params,
                                        hidl_vec<hidl_vec<uint8_t>>* outChain) override {
        if (!outChain) return ErrorCode::OUTPUT_PARAMETER_NULL;

        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeString16(name);
        nullable(writeParamSetToParcel, params, &data);

        status_t status = remote()->transact(BnKeystoreService::ATTEST_KEY, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("attestkey() count not contact remote: %d\n", status);
            return ResponseCode::SYSTEM_ERROR;
        }
        int32_t err = reply.readExceptionCode();
        ResponseCode ret = ResponseCode(reply.readInt32());
        if (err < 0) {
            ALOGD("attestKey() caught exception %d\n", err);
            return ResponseCode::SYSTEM_ERROR;
        }
        if (reply.readInt32() != 0) {
            *outChain = readCertificateChainFromParcel(reply);
        }
        return ret;
    }

    KeyStoreServiceReturnCode attestDeviceIds(const hidl_vec<KeyParameter>& params,
                                              hidl_vec<hidl_vec<uint8_t>>* outChain) override {
        if (!outChain) return ErrorCode::OUTPUT_PARAMETER_NULL;

        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        nullable(writeParamSetToParcel, params, &data);

        status_t status = remote()->transact(BnKeystoreService::ATTEST_DEVICE_IDS, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("attestDeviceIds() count not contact remote: %d\n", status);
            return ResponseCode::SYSTEM_ERROR;
        }
        int32_t err = reply.readExceptionCode();
        ResponseCode ret = ResponseCode(reply.readInt32());
        if (err < 0) {
            ALOGD("attestDeviceIds() caught exception %d\n", err);
            return ResponseCode::SYSTEM_ERROR;
        }
        if (reply.readInt32() != 0) {
            *outChain = readCertificateChainFromParcel(reply);
        }
        return ret;
    }

    KeyStoreServiceReturnCode onDeviceOffBody() override {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        status_t status = remote()->transact(BnKeystoreService::ON_DEVICE_OFF_BODY, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("onDeviceOffBody() could not contact remote: %d\n", status);
            return ResponseCode::SYSTEM_ERROR;
        }
        int32_t err = reply.readExceptionCode();
        if (err < 0) {
            ALOGD("onDeviceOffBody() caught exception %d\n", err);
            return ResponseCode::SYSTEM_ERROR;
        }
        return ResponseCode(reply.readInt32());
    }
};

IMPLEMENT_META_INTERFACE(KeystoreService, "android.security.IKeystoreService");

// ----------------------------------------------------------------------

status_t BnKeystoreService::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
                                       uint32_t flags) {
    switch (code) {
    case GET_STATE: {
        CHECK_INTERFACE(IKeystoreService, data, reply);
        int32_t userId = data.readInt32();
        int32_t ret = getState(userId);
        reply->writeNoException();
        reply->writeInt32(ret);
        return NO_ERROR;
    } break;
    case GET: {
        CHECK_INTERFACE(IKeystoreService, data, reply);
        String16 name = data.readString16();
        int32_t uid = data.readInt32();
        hidl_vec<uint8_t> out;
        auto ret = get(name, uid, &out);
        reply->writeNoException();
        if (ret.isOk()) {
            writeBlobAsByteArray(out, reply);
        } else {
            reply->writeInt32(-1);
        }
        reply->writeInt32(ret);
        return NO_ERROR;
    } break;
    case INSERT: {
        CHECK_INTERFACE(IKeystoreService, data, reply);
        String16 name = data.readString16();
        auto in = readBlobAsByteArray(data);
        int uid = data.readInt32();
        int32_t flags = data.readInt32();
        int32_t ret = insert(name, in.value(), uid, flags);
        reply->writeNoException();
        reply->writeInt32(ret);
        return NO_ERROR;
    } break;
    case DEL: {
        CHECK_INTERFACE(IKeystoreService, data, reply);
        String16 name = data.readString16();
        int uid = data.readInt32();
        int32_t ret = del(name, uid);
        reply->writeNoException();
        reply->writeInt32(ret);
        return NO_ERROR;
    } break;
    case EXIST: {
        CHECK_INTERFACE(IKeystoreService, data, reply);
        String16 name = data.readString16();
        int uid = data.readInt32();
        int32_t ret = exist(name, uid);
        reply->writeNoException();
        reply->writeInt32(ret);
        return NO_ERROR;
    } break;
    case LIST: {
        CHECK_INTERFACE(IKeystoreService, data, reply);
        String16 prefix = data.readString16();
        int uid = data.readInt32();
        Vector<String16> matches;
        int32_t ret = list(prefix, uid, &matches);
        reply->writeNoException();
        reply->writeInt32(matches.size());
        Vector<String16>::const_iterator it = matches.begin();
        for (; it != matches.end(); ++it) {
            reply->writeString16(*it);
        }
        reply->writeInt32(ret);
        return NO_ERROR;
    } break;
    case RESET: {
        CHECK_INTERFACE(IKeystoreService, data, reply);
        int32_t ret = reset();
        reply->writeNoException();
        reply->writeInt32(ret);
        return NO_ERROR;
    } break;
    case ON_USER_PASSWORD_CHANGED: {
        CHECK_INTERFACE(IKeystoreService, data, reply);
        int32_t userId = data.readInt32();
        String16 pass = data.readString16();
        int32_t ret = onUserPasswordChanged(userId, pass);
        reply->writeNoException();
        reply->writeInt32(ret);
        return NO_ERROR;
    } break;
    case LOCK: {
        CHECK_INTERFACE(IKeystoreService, data, reply);
        int32_t userId = data.readInt32();
        int32_t ret = lock(userId);
        reply->writeNoException();
        reply->writeInt32(ret);
        return NO_ERROR;
    } break;
    case UNLOCK: {
        CHECK_INTERFACE(IKeystoreService, data, reply);
        int32_t userId = data.readInt32();
        String16 pass = data.readString16();
        int32_t ret = unlock(userId, pass);
        reply->writeNoException();
        reply->writeInt32(ret);
        return NO_ERROR;
    } break;
    case IS_EMPTY: {
        CHECK_INTERFACE(IKeystoreService, data, reply);
        int32_t userId = data.readInt32();
        bool ret = isEmpty(userId);
        reply->writeNoException();
        reply->writeInt32(ret ? 1 : 0);
        return NO_ERROR;
    } break;
    case GENERATE: {
        CHECK_INTERFACE(IKeystoreService, data, reply);
        String16 name = data.readString16();
        int32_t uid = data.readInt32();
        int32_t keyType = data.readInt32();
        int32_t keySize = data.readInt32();
        int32_t flags = data.readInt32();
        Vector<sp<KeystoreArg>> args;
        int32_t argsPresent = data.readInt32();
        if (argsPresent == 1) {
            ssize_t numArgs = data.readInt32();
            if (numArgs > MAX_GENERATE_ARGS) {
                return BAD_VALUE;
            }
            if (numArgs > 0) {
                for (size_t i = 0; i < (size_t)numArgs; i++) {
                    ssize_t inSize = data.readInt32();
                    if (inSize >= 0 && (size_t)inSize <= data.dataAvail()) {
                        sp<KeystoreArg> arg = new KeystoreArg(data.readInplace(inSize), inSize);
                        args.push_back(arg);
                    } else {
                        args.push_back(NULL);
                    }
                }
            }
        }
        int32_t ret = generate(name, uid, keyType, keySize, flags, &args);
        reply->writeNoException();
        reply->writeInt32(ret);
        return NO_ERROR;
    } break;
    case IMPORT: {
        CHECK_INTERFACE(IKeystoreService, data, reply);
        String16 name = data.readString16();
        auto in = readBlobAsByteArray(data);
        int uid = data.readInt32();
        int32_t flags = data.readInt32();
        auto ret = import(name, in.value(), uid, flags);
        reply->writeNoException();
        reply->writeInt32(ret);
        return NO_ERROR;
    } break;
    case SIGN: {
        CHECK_INTERFACE(IKeystoreService, data, reply);
        String16 name = data.readString16();
        auto in = readBlobAsByteArray(data);
        hidl_vec<uint8_t> out;
        auto ret = sign(name, in.value(), &out);
        reply->writeNoException();
        writeBlobAsByteArray(out, reply);
        reply->writeInt32(ret);
        return NO_ERROR;
    } break;
    case VERIFY: {
        CHECK_INTERFACE(IKeystoreService, data, reply);
        String16 name = data.readString16();
        auto in = readBlobAsByteArray(data);
        auto signature = readBlobAsByteArray(data);
        auto ret = verify(name, in.value(), signature.value());
        reply->writeNoException();
        reply->writeInt32(ret);
        return NO_ERROR;
    } break;
    case GET_PUBKEY: {
        CHECK_INTERFACE(IKeystoreService, data, reply);
        String16 name = data.readString16();
        hidl_vec<uint8_t> out;
        auto ret = get_pubkey(name, &out);
        reply->writeNoException();
        writeBlobAsByteArray(out, reply);
        reply->writeInt32(ret);
        return NO_ERROR;
    } break;
    case GRANT: {
        CHECK_INTERFACE(IKeystoreService, data, reply);
        String16 name = data.readString16();
        int32_t granteeUid = data.readInt32();
        int32_t ret = grant(name, granteeUid);
        reply->writeNoException();
        reply->writeInt32(ret);
        return NO_ERROR;
    } break;
    case UNGRANT: {
        CHECK_INTERFACE(IKeystoreService, data, reply);
        String16 name = data.readString16();
        int32_t granteeUid = data.readInt32();
        int32_t ret = ungrant(name, granteeUid);
        reply->writeNoException();
        reply->writeInt32(ret);
        return NO_ERROR;
    } break;
    case GETMTIME: {
        CHECK_INTERFACE(IKeystoreService, data, reply);
        String16 name = data.readString16();
        int32_t uid = data.readInt32();
        int64_t ret = getmtime(name, uid);
        reply->writeNoException();
        reply->writeInt64(ret);
        return NO_ERROR;
    } break;
    case DUPLICATE: {
        CHECK_INTERFACE(IKeystoreService, data, reply);
        String16 srcKey = data.readString16();
        int32_t srcUid = data.readInt32();
        String16 destKey = data.readString16();
        int32_t destUid = data.readInt32();
        int32_t ret = duplicate(srcKey, srcUid, destKey, destUid);
        reply->writeNoException();
        reply->writeInt32(ret);
        return NO_ERROR;
    } break;
    case IS_HARDWARE_BACKED: {
        CHECK_INTERFACE(IKeystoreService, data, reply);
        String16 keyType = data.readString16();
        int32_t ret = is_hardware_backed(keyType);
        reply->writeNoException();
        reply->writeInt32(ret);
        return NO_ERROR;
    }
    case CLEAR_UID: {
        CHECK_INTERFACE(IKeystoreService, data, reply);
        int64_t uid = data.readInt64();
        int32_t ret = clear_uid(uid);
        reply->writeNoException();
        reply->writeInt32(ret);
        return NO_ERROR;
    }
    case ADD_RNG_ENTROPY: {
        CHECK_INTERFACE(IKeystoreService, data, reply);
        auto entropy = readBlobAsByteArray(data);
        auto ret = addRngEntropy(entropy.value());
        reply->writeNoException();
        reply->writeInt32(ret);
        return NO_ERROR;
    }
    case GENERATE_KEY: {
        CHECK_INTERFACE(IKeystoreService, data, reply);
        String16 name = data.readString16();
        auto params = nullable(readParamSetFromParcel, data);
        auto entropy = readBlobAsByteArray(data);
        int32_t uid = data.readInt32();
        int32_t flags = data.readInt32();
        KeyCharacteristics outCharacteristics;
        int32_t ret =
            generateKey(name, params.value(), entropy.value(), uid, flags, &outCharacteristics);
        reply->writeNoException();
        reply->writeInt32(ret);
        nullable(writeKeyCharacteristicsToParcel, outCharacteristics, reply);
        return NO_ERROR;
    }
    case GET_KEY_CHARACTERISTICS: {
        CHECK_INTERFACE(IKeystoreService, data, reply);
        String16 name = data.readString16();
        auto clientId = nullable(readKeymasterBlob, data, true);
        auto appData = nullable(readKeymasterBlob, data, true);
        int32_t uid = data.readInt32();
        KeyCharacteristics outCharacteristics;
        int ret = getKeyCharacteristics(name, clientId.value(), appData.value(), uid,
                                        &outCharacteristics);
        reply->writeNoException();
        reply->writeInt32(ret);
        nullable(writeKeyCharacteristicsToParcel, outCharacteristics, reply);
        return NO_ERROR;
    }
    case IMPORT_KEY: {
        CHECK_INTERFACE(IKeystoreService, data, reply);
        String16 name = data.readString16();
        auto args = nullable(readParamSetFromParcel, data);
        KeyFormat format = static_cast<KeyFormat>(data.readInt32());
        auto keyData = readBlobAsByteArray(data);
        int32_t uid = data.readInt32();
        int32_t flags = data.readInt32();
        KeyCharacteristics outCharacteristics;
        int32_t ret =
            importKey(name, args.value(), format, keyData.value(), uid, flags, &outCharacteristics);
        reply->writeNoException();
        reply->writeInt32(ret);
        nullable(writeKeyCharacteristicsToParcel, outCharacteristics, reply);
        return NO_ERROR;
    }
    case EXPORT_KEY: {
        CHECK_INTERFACE(IKeystoreService, data, reply);
        String16 name = data.readString16();
        KeyFormat format = static_cast<KeyFormat>(data.readInt32());
        auto clientId = nullable(readKeymasterBlob, data, true);
        auto appData = nullable(readKeymasterBlob, data, true);
        int32_t uid = data.readInt32();
        ExportResult result;
        exportKey(name, format, clientId.value(), appData.value(), uid, &result);
        reply->writeNoException();
        reply->writeParcelable(result);

        return NO_ERROR;
    }
    case BEGIN: {
        CHECK_INTERFACE(IKeystoreService, data, reply);
        sp<IBinder> token = data.readStrongBinder();
        String16 name = data.readString16();
        KeyPurpose purpose = static_cast<KeyPurpose>(data.readInt32());
        bool pruneable = data.readInt32() != 0;
        auto args = nullable(readParamSetFromParcel, data);
        auto entropy = readBlobAsByteArray(data);
        int32_t uid = data.readInt32();
        OperationResult result;
        begin(token, name, purpose, pruneable, args.value(), entropy.value(), uid, &result);
        reply->writeNoException();
        reply->writeParcelable(result);

        return NO_ERROR;
    }
    case UPDATE: {
        CHECK_INTERFACE(IKeystoreService, data, reply);
        sp<IBinder> token = data.readStrongBinder();
        auto args = nullable(readParamSetFromParcel, data);
        auto buf = readBlobAsByteArray(data);
        OperationResult result;
        update(token, args.value(), buf.value(), &result);
        reply->writeNoException();
        reply->writeParcelable(result);

        return NO_ERROR;
    }
    case FINISH: {
        CHECK_INTERFACE(IKeystoreService, data, reply);
        sp<IBinder> token = data.readStrongBinder();
        auto args = nullable(readParamSetFromParcel, data);
        auto signature = readBlobAsByteArray(data);
        auto entropy = readBlobAsByteArray(data);
        OperationResult result;
        finish(token, args.value(), signature.value(), entropy.value(), &result);
        reply->writeNoException();
        reply->writeParcelable(result);

        return NO_ERROR;
    }
    case ABORT: {
        CHECK_INTERFACE(IKeystoreService, data, reply);
        sp<IBinder> token = data.readStrongBinder();
        int32_t result = abort(token);
        reply->writeNoException();
        reply->writeInt32(result);

        return NO_ERROR;
    }
    case IS_OPERATION_AUTHORIZED: {
        CHECK_INTERFACE(IKeystoreService, data, reply);
        sp<IBinder> token = data.readStrongBinder();
        bool result = isOperationAuthorized(token);
        reply->writeNoException();
        reply->writeInt32(result ? 1 : 0);

        return NO_ERROR;
    }
    case ADD_AUTH_TOKEN: {
        CHECK_INTERFACE(IKeystoreService, data, reply);
        const uint8_t* token_bytes = NULL;
        size_t size = 0;
        readByteArray(data, &token_bytes, &size);
        int32_t result = addAuthToken(token_bytes, size);
        reply->writeNoException();
        reply->writeInt32(result);

        return NO_ERROR;
    }
    case ON_USER_ADDED: {
        CHECK_INTERFACE(IKeystoreService, data, reply);
        int32_t userId = data.readInt32();
        int32_t parentId = data.readInt32();
        int32_t result = onUserAdded(userId, parentId);
        reply->writeNoException();
        reply->writeInt32(result);

        return NO_ERROR;
    }
    case ON_USER_REMOVED: {
        CHECK_INTERFACE(IKeystoreService, data, reply);
        int32_t userId = data.readInt32();
        int32_t result = onUserRemoved(userId);
        reply->writeNoException();
        reply->writeInt32(result);

        return NO_ERROR;
    }
    case ATTEST_KEY: {
        CHECK_INTERFACE(IKeystoreService, data, reply);
        String16 name = data.readString16();
        auto params = nullable(readParamSetFromParcel, data);
        hidl_vec<hidl_vec<uint8_t>> chain;
        int ret = attestKey(name, params.value(), &chain);
        reply->writeNoException();
        reply->writeInt32(ret);
        nullable(writeCertificateChainToParcel, chain, reply);

        return NO_ERROR;
    }

    case ATTEST_DEVICE_IDS: {
        CHECK_INTERFACE(IKeystoreService, data, reply);
        auto params = nullable(readParamSetFromParcel, data);
        hidl_vec<hidl_vec<uint8_t>> chain;
        int ret = attestDeviceIds(params.value(), &chain);
        reply->writeNoException();
        reply->writeInt32(ret);
        nullable(writeCertificateChainToParcel, chain, reply);

        return NO_ERROR;
    }

    case ON_DEVICE_OFF_BODY: {
        CHECK_INTERFACE(IKeystoreService, data, reply);
        int32_t ret = onDeviceOffBody();
        reply->writeNoException();
        reply->writeInt32(ret);

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

// ----------------------------------------------------------------------------

};  // namespace android