blob: 5732613fe7eff94b4765163d4dc2a0f60f7e7440 [file] [log] [blame]
Jeff Tinkera53d6552017-01-20 00:31:46 -08001/*
2 * Copyright (C) 2017 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 "CryptoHal"
19#include <utils/Log.h>
20#include <dirent.h>
21#include <dlfcn.h>
22
23#include <android/hardware/drm/1.0/types.h>
24
25#include <binder/IMemory.h>
26#include <cutils/native_handle.h>
27#include <media/CryptoHal.h>
28#include <media/hardware/CryptoAPI.h>
29#include <media/stagefright/foundation/ADebug.h>
30#include <media/stagefright/foundation/AString.h>
31#include <media/stagefright/foundation/hexdump.h>
32#include <media/stagefright/MediaErrors.h>
33
34using ::android::hardware::drm::V1_0::BufferType;
35using ::android::hardware::drm::V1_0::DestinationBuffer;
36using ::android::hardware::drm::V1_0::ICryptoFactory;
37using ::android::hardware::drm::V1_0::ICryptoPlugin;
38using ::android::hardware::drm::V1_0::Mode;
39using ::android::hardware::drm::V1_0::Pattern;
40using ::android::hardware::drm::V1_0::SharedBuffer;
41using ::android::hardware::drm::V1_0::Status;
42using ::android::hardware::drm::V1_0::SubSample;
43using ::android::hardware::hidl_array;
44using ::android::hardware::hidl_handle;
45using ::android::hardware::hidl_memory;
46using ::android::hardware::hidl_string;
47using ::android::hardware::hidl_vec;
48using ::android::hardware::Return;
49using ::android::hardware::Void;
50using ::android::sp;
51
52
53namespace android {
54
55static status_t toStatusT(Status status) {
56 switch (status) {
57 case Status::OK:
58 return OK;
59 case Status::ERROR_DRM_NO_LICENSE:
60 return ERROR_DRM_NO_LICENSE;
61 case Status::ERROR_DRM_LICENSE_EXPIRED:
62 return ERROR_DRM_LICENSE_EXPIRED;
63 case Status::ERROR_DRM_RESOURCE_BUSY:
64 return ERROR_DRM_RESOURCE_BUSY;
65 case Status::ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION:
66 return ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION;
67 case Status::ERROR_DRM_SESSION_NOT_OPENED:
68 return ERROR_DRM_SESSION_NOT_OPENED;
69 case Status::ERROR_DRM_CANNOT_HANDLE:
70 return ERROR_DRM_CANNOT_HANDLE;
71 default:
72 return UNKNOWN_ERROR;
73 }
74}
75
76
77static hidl_vec<uint8_t> toHidlVec(const Vector<uint8_t> &vector) {
78 hidl_vec<uint8_t> vec;
79 vec.setToExternal(const_cast<uint8_t *>(vector.array()), vector.size());
80 return vec;
81}
82
83static hidl_vec<uint8_t> toHidlVec(const void *ptr, size_t size) {
84 hidl_vec<uint8_t> vec;
85 vec.resize(size);
86 memcpy(vec.data(), ptr, size);
87 return vec;
88}
89
90static hidl_array<uint8_t, 16> toHidlArray16(const uint8_t *ptr) {
91 if (!ptr) {
92 return hidl_array<uint8_t, 16>();
93 }
94 return hidl_array<uint8_t, 16>(ptr);
95}
96
97
Jeff Tinkera53d6552017-01-20 00:31:46 -080098static String8 toString8(hidl_string hString) {
99 return String8(hString.c_str());
100}
101
102
103CryptoHal::CryptoHal()
104 : mFactory(makeCryptoFactory()),
105 mInitCheck((mFactory == NULL) ? ERROR_UNSUPPORTED : NO_INIT),
Jeff Tinker3cb53162017-02-16 12:06:32 -0800106 mNextBufferId(0) {
Jeff Tinkera53d6552017-01-20 00:31:46 -0800107}
108
109CryptoHal::~CryptoHal() {
110}
111
112
113sp<ICryptoFactory> CryptoHal::makeCryptoFactory() {
114 sp<ICryptoFactory> factory = ICryptoFactory::getService("crypto");
115 if (factory == NULL) {
116 ALOGE("Failed to make crypto factory");
117 }
118 return factory;
119}
120
121sp<ICryptoPlugin> CryptoHal::makeCryptoPlugin(const uint8_t uuid[16],
122 const void *initData, size_t initDataSize) {
123 if (mFactory == NULL){
124 return NULL;
125 }
126
127 sp<ICryptoPlugin> plugin;
128 Return<void> hResult = mFactory->createPlugin(toHidlArray16(uuid),
129 toHidlVec(initData, initDataSize),
130 [&](Status status, const sp<ICryptoPlugin>& hPlugin) {
131 if (status != Status::OK) {
132 ALOGE("Failed to make crypto plugin");
133 return;
134 }
135 plugin = hPlugin;
136 }
137 );
138 return plugin;
139}
140
141
142status_t CryptoHal::initCheck() const {
143 return mInitCheck;
144}
145
146
147bool CryptoHal::isCryptoSchemeSupported(const uint8_t uuid[16]) {
148 Mutex::Autolock autoLock(mLock);
149 if (mFactory != NULL) {
150 return mFactory->isCryptoSchemeSupported(uuid);
151 }
152 return false;
153}
154
155status_t CryptoHal::createPlugin(
156 const uint8_t uuid[16], const void *data, size_t size) {
157 Mutex::Autolock autoLock(mLock);
158
159 mPlugin = makeCryptoPlugin(uuid, data, size);
160
161 if (mPlugin == NULL) {
162 mInitCheck = ERROR_UNSUPPORTED;
163 } else {
164 mInitCheck = OK;
165 }
166
167 return mInitCheck;
168}
169
170status_t CryptoHal::destroyPlugin() {
171 Mutex::Autolock autoLock(mLock);
172
173 if (mInitCheck != OK) {
174 return mInitCheck;
175 }
176
177 mPlugin.clear();
178 return OK;
179}
180
181bool CryptoHal::requiresSecureDecoderComponent(const char *mime) const {
182 Mutex::Autolock autoLock(mLock);
183
184 if (mInitCheck != OK) {
185 return mInitCheck;
186 }
187
188 return mPlugin->requiresSecureDecoderComponent(hidl_string(mime));
189}
190
191
192/**
193 * If the heap base isn't set, get the heap base from the IMemory
194 * and send it to the HAL so it can map a remote heap of the same
195 * size. Once the heap base is established, shared memory buffers
196 * are sent by providing an offset into the heap and a buffer size.
197 */
Jeff Tinker3cb53162017-02-16 12:06:32 -0800198void CryptoHal::setHeapBase(const sp<IMemoryHeap>& heap) {
199 native_handle_t* nativeHandle = native_handle_create(1, 0);
200 if (!nativeHandle) {
201 ALOGE("setSharedBufferBase(), failed to create native handle");
202 return;
Jeff Tinkera53d6552017-01-20 00:31:46 -0800203 }
Jeff Tinker3cb53162017-02-16 12:06:32 -0800204 if (heap == NULL) {
205 ALOGE("setSharedBufferBase(): heap is NULL");
206 return;
207 }
208 int fd = heap->getHeapID();
209 nativeHandle->data[0] = fd;
210 auto hidlHandle = hidl_handle(nativeHandle);
211 auto hidlMemory = hidl_memory("ashmem", hidlHandle, heap->getSize());
212 mHeapBases.add(heap->getBase(), mNextBufferId);
213 Return<void> hResult = mPlugin->setSharedBufferBase(hidlMemory, mNextBufferId++);
214 ALOGE_IF(!hResult.isOk(), "setSharedBufferBase(): remote call failed");
215}
216
217status_t CryptoHal::toSharedBuffer(const sp<IMemory>& memory, ::SharedBuffer* buffer) {
218 ssize_t offset;
219 size_t size;
220
221 if (memory == NULL && buffer == NULL) {
222 return UNEXPECTED_NULL;
223 }
224
225 sp<IMemoryHeap> heap = memory->getMemory(&offset, &size);
226 if (heap == NULL) {
227 return UNEXPECTED_NULL;
228 }
229
230 if (mHeapBases.indexOfKey(heap->getBase()) < 0) {
231 setHeapBase(heap);
232 }
233
234 buffer->bufferId = mHeapBases.valueFor(heap->getBase());
235 buffer->offset = offset >= 0 ? offset : 0;
236 buffer->size = size;
Jeff Tinkera53d6552017-01-20 00:31:46 -0800237 return OK;
238}
239
240ssize_t CryptoHal::decrypt(const uint8_t keyId[16], const uint8_t iv[16],
241 CryptoPlugin::Mode mode, const CryptoPlugin::Pattern &pattern,
242 const sp<IMemory> &source, size_t offset,
243 const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
244 const ICrypto::DestinationBuffer &destination, AString *errorDetailMsg) {
245 Mutex::Autolock autoLock(mLock);
246
247 if (mInitCheck != OK) {
248 return mInitCheck;
249 }
250
Jeff Tinkera53d6552017-01-20 00:31:46 -0800251 Mode hMode;
252 switch(mode) {
253 case CryptoPlugin::kMode_Unencrypted:
254 hMode = Mode::UNENCRYPTED ;
255 break;
256 case CryptoPlugin::kMode_AES_CTR:
257 hMode = Mode::AES_CTR;
258 break;
259 case CryptoPlugin::kMode_AES_WV:
260 hMode = Mode::AES_CBC_CTS;
261 break;
262 case CryptoPlugin::kMode_AES_CBC:
263 hMode = Mode::AES_CBC;
264 break;
265 default:
266 return UNKNOWN_ERROR;
267 }
268
269 Pattern hPattern;
270 hPattern.encryptBlocks = pattern.mEncryptBlocks;
271 hPattern.skipBlocks = pattern.mSkipBlocks;
272
273 std::vector<SubSample> stdSubSamples;
274 for (size_t i = 0; i < numSubSamples; i++) {
275 SubSample subSample;
276 subSample.numBytesOfClearData = subSamples[i].mNumBytesOfClearData;
277 subSample.numBytesOfEncryptedData = subSamples[i].mNumBytesOfEncryptedData;
278 stdSubSamples.push_back(subSample);
279 }
280 auto hSubSamples = hidl_vec<SubSample>(stdSubSamples);
281
282 bool secure;
283 ::DestinationBuffer hDestination;
284 if (destination.mType == kDestinationTypeSharedMemory) {
285 hDestination.type = BufferType::SHARED_MEMORY;
Jeff Tinker3cb53162017-02-16 12:06:32 -0800286 status_t status = toSharedBuffer(destination.mSharedMemory,
287 &hDestination.nonsecureMemory);
288 if (status != OK) {
289 return status;
290 }
Jeff Tinkera53d6552017-01-20 00:31:46 -0800291 secure = false;
292 } else {
293 hDestination.type = BufferType::NATIVE_HANDLE;
294 hDestination.secureMemory = hidl_handle(destination.mHandle);
295 secure = true;
296 }
297
Jeff Tinker3cb53162017-02-16 12:06:32 -0800298 ::SharedBuffer hSource;
299 status_t status = toSharedBuffer(source, &hSource);
300 if (status != OK) {
301 return status;
302 }
Jeff Tinkera53d6552017-01-20 00:31:46 -0800303
304 status_t err = UNKNOWN_ERROR;
305 uint32_t bytesWritten = 0;
306
307 Return<void> hResult = mPlugin->decrypt(secure, toHidlArray16(keyId), toHidlArray16(iv), hMode,
Jeff Tinker3cb53162017-02-16 12:06:32 -0800308 hPattern, hSubSamples, hSource, offset, hDestination,
Jeff Tinkera53d6552017-01-20 00:31:46 -0800309 [&](Status status, uint32_t hBytesWritten, hidl_string hDetailedError) {
310 if (status == Status::OK) {
311 bytesWritten = hBytesWritten;
312 *errorDetailMsg = toString8(hDetailedError);
313 }
314 err = toStatusT(status);
315 }
316 );
317
318 if (!hResult.isOk()) {
319 err = DEAD_OBJECT;
320 }
321
322 if (err == OK) {
323 return bytesWritten;
324 }
325 return err;
326}
327
328void CryptoHal::notifyResolution(uint32_t width, uint32_t height) {
329 Mutex::Autolock autoLock(mLock);
330
331 if (mInitCheck != OK) {
332 return;
333 }
334
335 mPlugin->notifyResolution(width, height);
336}
337
338status_t CryptoHal::setMediaDrmSession(const Vector<uint8_t> &sessionId) {
339 Mutex::Autolock autoLock(mLock);
340
341 if (mInitCheck != OK) {
342 return mInitCheck;
343 }
344
345 return toStatusT(mPlugin->setMediaDrmSession(toHidlVec(sessionId)));
346}
347
348} // namespace android