ICrypto.cpp revision c481b5012a5f6cf72e5e93b36f1ed4c9169916f2
1/* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17//#define LOG_NDEBUG 0 18#define LOG_TAG "ICrypto" 19#include <utils/Log.h> 20 21#include <binder/Parcel.h> 22#include <binder/IMemory.h> 23#include <media/ICrypto.h> 24#include <media/stagefright/MediaErrors.h> 25#include <media/stagefright/foundation/ADebug.h> 26#include <media/stagefright/foundation/AString.h> 27 28namespace android { 29 30enum { 31 INIT_CHECK = IBinder::FIRST_CALL_TRANSACTION, 32 IS_CRYPTO_SUPPORTED, 33 CREATE_PLUGIN, 34 DESTROY_PLUGIN, 35 REQUIRES_SECURE_COMPONENT, 36 DECRYPT, 37 NOTIFY_RESOLUTION, 38}; 39 40struct BpCrypto : public BpInterface<ICrypto> { 41 BpCrypto(const sp<IBinder> &impl) 42 : BpInterface<ICrypto>(impl) { 43 } 44 45 virtual status_t initCheck() const { 46 Parcel data, reply; 47 data.writeInterfaceToken(ICrypto::getInterfaceDescriptor()); 48 remote()->transact(INIT_CHECK, data, &reply); 49 50 return reply.readInt32(); 51 } 52 53 virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]) { 54 Parcel data, reply; 55 data.writeInterfaceToken(ICrypto::getInterfaceDescriptor()); 56 data.write(uuid, 16); 57 remote()->transact(IS_CRYPTO_SUPPORTED, data, &reply); 58 59 return reply.readInt32() != 0; 60 } 61 62 virtual status_t createPlugin( 63 const uint8_t uuid[16], const void *opaqueData, size_t opaqueSize) { 64 Parcel data, reply; 65 data.writeInterfaceToken(ICrypto::getInterfaceDescriptor()); 66 data.write(uuid, 16); 67 data.writeInt32(opaqueSize); 68 69 if (opaqueSize > 0) { 70 data.write(opaqueData, opaqueSize); 71 } 72 73 remote()->transact(CREATE_PLUGIN, data, &reply); 74 75 return reply.readInt32(); 76 } 77 78 virtual status_t destroyPlugin() { 79 Parcel data, reply; 80 data.writeInterfaceToken(ICrypto::getInterfaceDescriptor()); 81 remote()->transact(DESTROY_PLUGIN, data, &reply); 82 83 return reply.readInt32(); 84 } 85 86 virtual bool requiresSecureDecoderComponent( 87 const char *mime) const { 88 Parcel data, reply; 89 data.writeInterfaceToken(ICrypto::getInterfaceDescriptor()); 90 data.writeCString(mime); 91 remote()->transact(REQUIRES_SECURE_COMPONENT, data, &reply); 92 93 return reply.readInt32() != 0; 94 } 95 96 virtual ssize_t decrypt( 97 bool secure, 98 const uint8_t key[16], 99 const uint8_t iv[16], 100 CryptoPlugin::Mode mode, 101 const sp<IMemory> &sharedBuffer, size_t offset, 102 const CryptoPlugin::SubSample *subSamples, size_t numSubSamples, 103 void *dstPtr, 104 AString *errorDetailMsg) { 105 Parcel data, reply; 106 data.writeInterfaceToken(ICrypto::getInterfaceDescriptor()); 107 data.writeInt32(secure); 108 data.writeInt32(mode); 109 110 static const uint8_t kDummy[16] = { 0 }; 111 112 if (key == NULL) { 113 key = kDummy; 114 } 115 116 if (iv == NULL) { 117 iv = kDummy; 118 } 119 120 data.write(key, 16); 121 data.write(iv, 16); 122 123 size_t totalSize = 0; 124 for (size_t i = 0; i < numSubSamples; ++i) { 125 totalSize += subSamples[i].mNumBytesOfEncryptedData; 126 totalSize += subSamples[i].mNumBytesOfClearData; 127 } 128 129 data.writeInt32(totalSize); 130 data.writeStrongBinder(IInterface::asBinder(sharedBuffer)); 131 data.writeInt32(offset); 132 133 data.writeInt32(numSubSamples); 134 data.write(subSamples, sizeof(CryptoPlugin::SubSample) * numSubSamples); 135 136 if (secure) { 137 data.writeInt64(static_cast<uint64_t>(reinterpret_cast<uintptr_t>(dstPtr))); 138 } 139 140 remote()->transact(DECRYPT, data, &reply); 141 142 ssize_t result = reply.readInt32(); 143 144 if (result >= ERROR_DRM_VENDOR_MIN && result <= ERROR_DRM_VENDOR_MAX) { 145 errorDetailMsg->setTo(reply.readCString()); 146 } 147 148 if (!secure && result >= 0) { 149 reply.read(dstPtr, result); 150 } 151 152 return result; 153 } 154 155 virtual void notifyResolution( 156 uint32_t width, uint32_t height) { 157 Parcel data, reply; 158 data.writeInterfaceToken(ICrypto::getInterfaceDescriptor()); 159 data.writeInt32(width); 160 data.writeInt32(height); 161 remote()->transact(NOTIFY_RESOLUTION, data, &reply); 162 } 163 164private: 165 DISALLOW_EVIL_CONSTRUCTORS(BpCrypto); 166}; 167 168IMPLEMENT_META_INTERFACE(Crypto, "android.hardware.ICrypto"); 169 170//////////////////////////////////////////////////////////////////////////////// 171 172status_t BnCrypto::onTransact( 173 uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) { 174 switch (code) { 175 case INIT_CHECK: 176 { 177 CHECK_INTERFACE(ICrypto, data, reply); 178 reply->writeInt32(initCheck()); 179 180 return OK; 181 } 182 183 case IS_CRYPTO_SUPPORTED: 184 { 185 CHECK_INTERFACE(ICrypto, data, reply); 186 uint8_t uuid[16]; 187 data.read(uuid, sizeof(uuid)); 188 reply->writeInt32(isCryptoSchemeSupported(uuid)); 189 190 return OK; 191 } 192 193 case CREATE_PLUGIN: 194 { 195 CHECK_INTERFACE(ICrypto, data, reply); 196 197 uint8_t uuid[16]; 198 data.read(uuid, sizeof(uuid)); 199 200 size_t opaqueSize = data.readInt32(); 201 void *opaqueData = NULL; 202 203 if (opaqueSize > 0) { 204 opaqueData = malloc(opaqueSize); 205 data.read(opaqueData, opaqueSize); 206 } 207 208 reply->writeInt32(createPlugin(uuid, opaqueData, opaqueSize)); 209 210 if (opaqueData != NULL) { 211 free(opaqueData); 212 opaqueData = NULL; 213 } 214 215 return OK; 216 } 217 218 case DESTROY_PLUGIN: 219 { 220 CHECK_INTERFACE(ICrypto, data, reply); 221 reply->writeInt32(destroyPlugin()); 222 223 return OK; 224 } 225 226 case REQUIRES_SECURE_COMPONENT: 227 { 228 CHECK_INTERFACE(ICrypto, data, reply); 229 230 const char *mime = data.readCString(); 231 reply->writeInt32(requiresSecureDecoderComponent(mime)); 232 233 return OK; 234 } 235 236 case DECRYPT: 237 { 238 CHECK_INTERFACE(ICrypto, data, reply); 239 240 bool secure = data.readInt32() != 0; 241 CryptoPlugin::Mode mode = (CryptoPlugin::Mode)data.readInt32(); 242 243 uint8_t key[16]; 244 data.read(key, sizeof(key)); 245 246 uint8_t iv[16]; 247 data.read(iv, sizeof(iv)); 248 249 size_t totalSize = data.readInt32(); 250 sp<IMemory> sharedBuffer = 251 interface_cast<IMemory>(data.readStrongBinder()); 252 int32_t offset = data.readInt32(); 253 254 int32_t numSubSamples = data.readInt32(); 255 256 CryptoPlugin::SubSample *subSamples = 257 new CryptoPlugin::SubSample[numSubSamples]; 258 259 data.read( 260 subSamples, 261 sizeof(CryptoPlugin::SubSample) * numSubSamples); 262 263 void *dstPtr; 264 if (secure) { 265 dstPtr = reinterpret_cast<void *>(static_cast<uintptr_t>(data.readInt64())); 266 } else { 267 dstPtr = malloc(totalSize); 268 } 269 270 AString errorDetailMsg; 271 ssize_t result; 272 273 if (offset + totalSize > sharedBuffer->size()) { 274 result = -EINVAL; 275 } else { 276 result = decrypt( 277 secure, 278 key, 279 iv, 280 mode, 281 sharedBuffer, offset, 282 subSamples, numSubSamples, 283 dstPtr, 284 &errorDetailMsg); 285 } 286 287 reply->writeInt32(result); 288 289 if (result >= ERROR_DRM_VENDOR_MIN 290 && result <= ERROR_DRM_VENDOR_MAX) { 291 reply->writeCString(errorDetailMsg.c_str()); 292 } 293 294 if (!secure) { 295 if (result >= 0) { 296 CHECK_LE(result, static_cast<ssize_t>(totalSize)); 297 reply->write(dstPtr, result); 298 } 299 free(dstPtr); 300 dstPtr = NULL; 301 } 302 303 delete[] subSamples; 304 subSamples = NULL; 305 306 return OK; 307 } 308 309 case NOTIFY_RESOLUTION: 310 { 311 CHECK_INTERFACE(ICrypto, data, reply); 312 313 int32_t width = data.readInt32(); 314 int32_t height = data.readInt32(); 315 notifyResolution(width, height); 316 317 return OK; 318 } 319 320 default: 321 return BBinder::onTransact(code, data, reply, flags); 322 } 323} 324 325} // namespace android 326