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