• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     NOTIFY_RESOLUTION,
37 };
38 
39 struct BpCrypto : public BpInterface<ICrypto> {
BpCryptoandroid::BpCrypto40     BpCrypto(const sp<IBinder> &impl)
41         : BpInterface<ICrypto>(impl) {
42     }
43 
initCheckandroid::BpCrypto44     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 
isCryptoSchemeSupportedandroid::BpCrypto52     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 
createPluginandroid::BpCrypto61     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 
destroyPluginandroid::BpCrypto77     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 
requiresSecureDecoderComponentandroid::BpCrypto85     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 
decryptandroid::BpCrypto95     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 
notifyResolutionandroid::BpCrypto153     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 
162 private:
163     DISALLOW_EVIL_CONSTRUCTORS(BpCrypto);
164 };
165 
166 IMPLEMENT_META_INTERFACE(Crypto, "android.hardware.ICrypto");
167 
168 ////////////////////////////////////////////////////////////////////////////////
169 
onTransact(uint32_t code,const Parcel & data,Parcel * reply,uint32_t flags)170 status_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