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