ICrypto.cpp revision 2514d080c8a54ff603a45d7e336de668fe7329db
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 <media/ICrypto.h> 23#include <media/stagefright/MediaErrors.h> 24#include <media/stagefright/foundation/ADebug.h> 25#include <media/stagefright/foundation/AString.h> 26 27namespace android { 28 29enum { 30 INIT_CHECK = IBinder::FIRST_CALL_TRANSACTION, 31 IS_CRYPTO_SUPPORTED, 32 CREATE_PLUGIN, 33 DESTROY_PLUGIN, 34 REQUIRES_SECURE_COMPONENT, 35 DECRYPT, 36 NOTIFY_RESOLUTION, 37}; 38 39struct BpCrypto : public BpInterface<ICrypto> { 40 BpCrypto(const sp<IBinder> &impl) 41 : BpInterface<ICrypto>(impl) { 42 } 43 44 virtual status_t initCheck() const { 45 Parcel data, reply; 46 data.writeInterfaceToken(ICrypto::getInterfaceDescriptor()); 47 remote()->transact(INIT_CHECK, data, &reply); 48 49 return reply.readInt32(); 50 } 51 52 virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]) { 53 Parcel data, reply; 54 data.writeInterfaceToken(ICrypto::getInterfaceDescriptor()); 55 data.write(uuid, 16); 56 remote()->transact(IS_CRYPTO_SUPPORTED, data, &reply); 57 58 return reply.readInt32() != 0; 59 } 60 61 virtual status_t createPlugin( 62 const uint8_t uuid[16], const void *opaqueData, size_t opaqueSize) { 63 Parcel data, reply; 64 data.writeInterfaceToken(ICrypto::getInterfaceDescriptor()); 65 data.write(uuid, 16); 66 data.writeInt32(opaqueSize); 67 68 if (opaqueSize > 0) { 69 data.write(opaqueData, opaqueSize); 70 } 71 72 remote()->transact(CREATE_PLUGIN, data, &reply); 73 74 return reply.readInt32(); 75 } 76 77 virtual status_t destroyPlugin() { 78 Parcel data, reply; 79 data.writeInterfaceToken(ICrypto::getInterfaceDescriptor()); 80 remote()->transact(DESTROY_PLUGIN, data, &reply); 81 82 return reply.readInt32(); 83 } 84 85 virtual bool requiresSecureDecoderComponent( 86 const char *mime) const { 87 Parcel data, reply; 88 data.writeInterfaceToken(ICrypto::getInterfaceDescriptor()); 89 data.writeCString(mime); 90 remote()->transact(REQUIRES_SECURE_COMPONENT, data, &reply); 91 92 return reply.readInt32() != 0; 93 } 94 95 virtual ssize_t decrypt( 96 bool secure, 97 const uint8_t key[16], 98 const uint8_t iv[16], 99 CryptoPlugin::Mode mode, 100 const void *srcPtr, 101 const CryptoPlugin::SubSample *subSamples, size_t numSubSamples, 102 void *dstPtr, 103 AString *errorDetailMsg) { 104 Parcel data, reply; 105 data.writeInterfaceToken(ICrypto::getInterfaceDescriptor()); 106 data.writeInt32(secure); 107 data.writeInt32(mode); 108 109 static const uint8_t kDummy[16] = { 0 }; 110 111 if (key == NULL) { 112 key = kDummy; 113 } 114 115 if (iv == NULL) { 116 iv = kDummy; 117 } 118 119 data.write(key, 16); 120 data.write(iv, 16); 121 122 size_t totalSize = 0; 123 for (size_t i = 0; i < numSubSamples; ++i) { 124 totalSize += subSamples[i].mNumBytesOfEncryptedData; 125 totalSize += subSamples[i].mNumBytesOfClearData; 126 } 127 128 data.writeInt32(totalSize); 129 data.write(srcPtr, totalSize); 130 131 data.writeInt32(numSubSamples); 132 data.write(subSamples, sizeof(CryptoPlugin::SubSample) * numSubSamples); 133 134 if (secure) { 135 data.writeInt64(static_cast<uint64_t>(reinterpret_cast<uintptr_t>(dstPtr))); 136 } 137 138 remote()->transact(DECRYPT, data, &reply); 139 140 ssize_t result = reply.readInt32(); 141 142 if (result >= ERROR_DRM_VENDOR_MIN && result <= ERROR_DRM_VENDOR_MAX) { 143 errorDetailMsg->setTo(reply.readCString()); 144 } 145 146 if (!secure && result >= 0) { 147 reply.read(dstPtr, result); 148 } 149 150 return result; 151 } 152 153 virtual void notifyResolution( 154 uint32_t width, uint32_t height) { 155 Parcel data, reply; 156 data.writeInterfaceToken(ICrypto::getInterfaceDescriptor()); 157 data.writeInt32(width); 158 data.writeInt32(height); 159 remote()->transact(NOTIFY_RESOLUTION, data, &reply); 160 } 161 162private: 163 DISALLOW_EVIL_CONSTRUCTORS(BpCrypto); 164}; 165 166IMPLEMENT_META_INTERFACE(Crypto, "android.hardware.ICrypto"); 167 168//////////////////////////////////////////////////////////////////////////////// 169 170status_t BnCrypto::onTransact( 171 uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) { 172 switch (code) { 173 case INIT_CHECK: 174 { 175 CHECK_INTERFACE(ICrypto, data, reply); 176 reply->writeInt32(initCheck()); 177 178 return OK; 179 } 180 181 case IS_CRYPTO_SUPPORTED: 182 { 183 CHECK_INTERFACE(ICrypto, data, reply); 184 uint8_t uuid[16]; 185 data.read(uuid, sizeof(uuid)); 186 reply->writeInt32(isCryptoSchemeSupported(uuid)); 187 188 return OK; 189 } 190 191 case CREATE_PLUGIN: 192 { 193 CHECK_INTERFACE(ICrypto, data, reply); 194 195 uint8_t uuid[16]; 196 data.read(uuid, sizeof(uuid)); 197 198 size_t opaqueSize = data.readInt32(); 199 void *opaqueData = NULL; 200 201 if (opaqueSize > 0) { 202 opaqueData = malloc(opaqueSize); 203 data.read(opaqueData, opaqueSize); 204 } 205 206 reply->writeInt32(createPlugin(uuid, opaqueData, opaqueSize)); 207 208 if (opaqueData != NULL) { 209 free(opaqueData); 210 opaqueData = NULL; 211 } 212 213 return OK; 214 } 215 216 case DESTROY_PLUGIN: 217 { 218 CHECK_INTERFACE(ICrypto, data, reply); 219 reply->writeInt32(destroyPlugin()); 220 221 return OK; 222 } 223 224 case REQUIRES_SECURE_COMPONENT: 225 { 226 CHECK_INTERFACE(ICrypto, data, reply); 227 228 const char *mime = data.readCString(); 229 reply->writeInt32(requiresSecureDecoderComponent(mime)); 230 231 return OK; 232 } 233 234 case DECRYPT: 235 { 236 CHECK_INTERFACE(ICrypto, data, reply); 237 238 bool secure = data.readInt32() != 0; 239 CryptoPlugin::Mode mode = (CryptoPlugin::Mode)data.readInt32(); 240 241 uint8_t key[16]; 242 data.read(key, sizeof(key)); 243 244 uint8_t iv[16]; 245 data.read(iv, sizeof(iv)); 246 247 size_t totalSize = data.readInt32(); 248 void *srcData = malloc(totalSize); 249 data.read(srcData, totalSize); 250 251 int32_t numSubSamples = data.readInt32(); 252 253 CryptoPlugin::SubSample *subSamples = 254 new CryptoPlugin::SubSample[numSubSamples]; 255 256 data.read( 257 subSamples, 258 sizeof(CryptoPlugin::SubSample) * numSubSamples); 259 260 void *dstPtr; 261 if (secure) { 262 dstPtr = reinterpret_cast<void *>(static_cast<uintptr_t>(data.readInt64())); 263 } else { 264 dstPtr = malloc(totalSize); 265 } 266 267 AString errorDetailMsg; 268 ssize_t result = decrypt( 269 secure, 270 key, 271 iv, 272 mode, 273 srcData, 274 subSamples, numSubSamples, 275 dstPtr, 276 &errorDetailMsg); 277 278 reply->writeInt32(result); 279 280 if (result >= ERROR_DRM_VENDOR_MIN 281 && result <= ERROR_DRM_VENDOR_MAX) { 282 reply->writeCString(errorDetailMsg.c_str()); 283 } 284 285 if (!secure) { 286 if (result >= 0) { 287 CHECK_LE(result, static_cast<ssize_t>(totalSize)); 288 reply->write(dstPtr, result); 289 } 290 free(dstPtr); 291 dstPtr = NULL; 292 } 293 294 delete[] subSamples; 295 subSamples = NULL; 296 297 free(srcData); 298 srcData = NULL; 299 300 return OK; 301 } 302 303 case NOTIFY_RESOLUTION: 304 { 305 CHECK_INTERFACE(ICrypto, data, reply); 306 307 int32_t width = data.readInt32(); 308 int32_t height = data.readInt32(); 309 notifyResolution(width, height); 310 311 return OK; 312 } 313 314 default: 315 return BBinder::onTransact(code, data, reply, flags); 316 } 317} 318 319} // namespace android 320