/* * 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, UNPROVISION_DEVICE, GET_SECURE_STOP, RELEASE_ALL_SECURE_STOPS }; struct BpDrm : public BpInterface<IDrm> { 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]) { Parcel data, reply; data.writeInterfaceToken(IDrm::getInterfaceDescriptor()); data.write(uuid, 16); status_t status = remote()->transact(CREATE_PLUGIN, data, &reply); if (status != OK) { 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 unprovisionDevice() { Parcel data, reply; data.writeInterfaceToken(IDrm::getInterfaceDescriptor()); status_t status = remote()->transact(UNPROVISION_DEVICE, data, &reply); if (status != OK) { return status; } 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)); reply->writeInt32(createPlugin(uuid)); 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; 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 UNPROVISION_DEVICE: { CHECK_INTERFACE(IDrm, data, reply); status_t result = unprovisionDevice(); 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; 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