blob: a29070461fd6bcb2caaf45af8ecc64e06fa5f0f5 [file] [log] [blame]
Kyle Zhang6605add2022-01-13 17:51:23 +00001/*
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 "CryptoHalHidl"
19#include <utils/Log.h>
20
21#include <android/hardware/drm/1.0/types.h>
22#include <android/hidl/manager/1.2/IServiceManager.h>
23#include <hidl/ServiceManagement.h>
24#include <hidlmemory/FrameworkUtils.h>
25#include <media/hardware/CryptoAPI.h>
26#include <media/stagefright/MediaErrors.h>
27#include <media/stagefright/foundation/ADebug.h>
28#include <media/stagefright/foundation/AString.h>
29#include <media/stagefright/foundation/hexdump.h>
30#include <mediadrm/CryptoHalHidl.h>
31#include <mediadrm/DrmUtils.h>
32
33using drm::V1_0::BufferType;
34using drm::V1_0::DestinationBuffer;
35using drm::V1_0::ICryptoFactory;
36using drm::V1_0::ICryptoPlugin;
37using drm::V1_0::Mode;
38using drm::V1_0::Pattern;
39using drm::V1_0::SharedBuffer;
40using drm::V1_0::Status;
41using drm::V1_0::SubSample;
42
43using ::android::sp;
44using ::android::DrmUtils::toStatusT;
45using ::android::hardware::hidl_array;
46using ::android::hardware::hidl_handle;
47using ::android::hardware::hidl_memory;
48using ::android::hardware::hidl_string;
49using ::android::hardware::hidl_vec;
50using ::android::hardware::HidlMemory;
51using ::android::hardware::Return;
52using ::android::hardware::Void;
53
54typedef drm::V1_2::Status Status_V1_2;
55
56namespace android {
57
58static hidl_vec<uint8_t> toHidlVec(const Vector<uint8_t>& vector) {
59 hidl_vec<uint8_t> vec;
60 vec.setToExternal(const_cast<uint8_t*>(vector.array()), vector.size());
61 return vec;
62}
63
64static hidl_vec<uint8_t> toHidlVec(const void* ptr, size_t size) {
65 hidl_vec<uint8_t> vec;
66 vec.resize(size);
67 memcpy(vec.data(), ptr, size);
68 return vec;
69}
70
71static hidl_array<uint8_t, 16> toHidlArray16(const uint8_t* ptr) {
72 if (!ptr) {
73 return hidl_array<uint8_t, 16>();
74 }
75 return hidl_array<uint8_t, 16>(ptr);
76}
77
78static String8 toString8(hidl_string hString) {
79 return String8(hString.c_str());
80}
81
82CryptoHalHidl::CryptoHalHidl()
83 : mFactories(makeCryptoFactories()),
84 mInitCheck((mFactories.size() == 0) ? ERROR_UNSUPPORTED : NO_INIT),
85 mHeapSeqNum(0) {}
86
87CryptoHalHidl::~CryptoHalHidl() {}
88
89Vector<sp<ICryptoFactory>> CryptoHalHidl::makeCryptoFactories() {
90 Vector<sp<ICryptoFactory>> factories;
91
92 auto manager = hardware::defaultServiceManager1_2();
93 if (manager != NULL) {
94 manager->listManifestByInterface(
95 drm::V1_0::ICryptoFactory::descriptor,
96 [&factories](const hidl_vec<hidl_string>& registered) {
97 for (const auto& instance : registered) {
98 auto factory = drm::V1_0::ICryptoFactory::getService(instance);
99 if (factory != NULL) {
100 ALOGD("found drm@1.0 ICryptoFactory %s", instance.c_str());
101 factories.push_back(factory);
102 }
103 }
104 });
105 manager->listManifestByInterface(
106 drm::V1_1::ICryptoFactory::descriptor,
107 [&factories](const hidl_vec<hidl_string>& registered) {
108 for (const auto& instance : registered) {
109 auto factory = drm::V1_1::ICryptoFactory::getService(instance);
110 if (factory != NULL) {
111 ALOGD("found drm@1.1 ICryptoFactory %s", instance.c_str());
112 factories.push_back(factory);
113 }
114 }
115 });
116 }
117
118 if (factories.size() == 0) {
119 // must be in passthrough mode, load the default passthrough service
120 auto passthrough = ICryptoFactory::getService();
121 if (passthrough != NULL) {
122 ALOGI("makeCryptoFactories: using default passthrough crypto instance");
123 factories.push_back(passthrough);
124 } else {
125 ALOGE("Failed to find any crypto factories");
126 }
127 }
128 return factories;
129}
130
131sp<ICryptoPlugin> CryptoHalHidl::makeCryptoPlugin(const sp<ICryptoFactory>& factory,
132 const uint8_t uuid[16], const void* initData,
133 size_t initDataSize) {
134 sp<ICryptoPlugin> plugin;
135 Return<void> hResult =
136 factory->createPlugin(toHidlArray16(uuid), toHidlVec(initData, initDataSize),
137 [&](Status status, const sp<ICryptoPlugin>& hPlugin) {
138 if (status != Status::OK) {
139 ALOGE("Failed to make crypto plugin");
140 return;
141 }
142 plugin = hPlugin;
143 });
144 if (!hResult.isOk()) {
145 mInitCheck = DEAD_OBJECT;
146 }
147 return plugin;
148}
149
150status_t CryptoHalHidl::initCheck() const {
151 return mInitCheck;
152}
153
154bool CryptoHalHidl::isCryptoSchemeSupported(const uint8_t uuid[16]) {
155 Mutex::Autolock autoLock(mLock);
156
157 for (size_t i = 0; i < mFactories.size(); i++) {
158 if (mFactories[i]->isCryptoSchemeSupported(uuid)) {
159 return true;
160 }
161 }
162 return false;
163}
164
165status_t CryptoHalHidl::createPlugin(const uint8_t uuid[16], const void* data, size_t size) {
166 Mutex::Autolock autoLock(mLock);
167
168 for (size_t i = 0; i < mFactories.size(); i++) {
169 if (mFactories[i]->isCryptoSchemeSupported(uuid)) {
170 mPlugin = makeCryptoPlugin(mFactories[i], uuid, data, size);
171 if (mPlugin != NULL) {
172 mPluginV1_2 = drm::V1_2::ICryptoPlugin::castFrom(mPlugin);
173 }
174 }
175 }
176
177 if (mInitCheck == NO_INIT) {
178 mInitCheck = mPlugin == NULL ? ERROR_UNSUPPORTED : OK;
179 }
180
181 return mInitCheck;
182}
183
184status_t CryptoHalHidl::destroyPlugin() {
185 Mutex::Autolock autoLock(mLock);
186
187 if (mInitCheck != OK) {
188 return mInitCheck;
189 }
190
191 mPlugin.clear();
192 mPluginV1_2.clear();
193 return OK;
194}
195
196bool CryptoHalHidl::requiresSecureDecoderComponent(const char* mime) const {
197 Mutex::Autolock autoLock(mLock);
198
199 if (mInitCheck != OK) {
200 return false;
201 }
202
203 Return<bool> hResult = mPlugin->requiresSecureDecoderComponent(hidl_string(mime));
204 if (!hResult.isOk()) {
205 return false;
206 }
207 return hResult;
208}
209
210/**
211 * If the heap base isn't set, get the heap base from the HidlMemory
212 * and send it to the HAL so it can map a remote heap of the same
213 * size. Once the heap base is established, shared memory buffers
214 * are sent by providing an offset into the heap and a buffer size.
215 */
216int32_t CryptoHalHidl::setHeapBase(const sp<HidlMemory>& heap) {
217 if (heap == NULL || mHeapSeqNum < 0) {
218 ALOGE("setHeapBase(): heap %p mHeapSeqNum %d", heap.get(), mHeapSeqNum);
219 return -1;
220 }
221
222 Mutex::Autolock autoLock(mLock);
223
224 int32_t seqNum = mHeapSeqNum++;
225 uint32_t bufferId = static_cast<uint32_t>(seqNum);
226 mHeapSizes.add(seqNum, heap->size());
227 Return<void> hResult = mPlugin->setSharedBufferBase(*heap, bufferId);
228 ALOGE_IF(!hResult.isOk(), "setSharedBufferBase(): remote call failed");
229 return seqNum;
230}
231
232void CryptoHalHidl::clearHeapBase(int32_t seqNum) {
233 Mutex::Autolock autoLock(mLock);
234
235 /*
236 * Clear the remote shared memory mapping by setting the shared
237 * buffer base to a null hidl_memory.
238 *
239 * TODO: Add a releaseSharedBuffer method in a future DRM HAL
240 * API version to make this explicit.
241 */
242 ssize_t index = mHeapSizes.indexOfKey(seqNum);
243 if (index >= 0) {
244 if (mPlugin != NULL) {
245 uint32_t bufferId = static_cast<uint32_t>(seqNum);
246 Return<void> hResult = mPlugin->setSharedBufferBase(hidl_memory(), bufferId);
247 ALOGE_IF(!hResult.isOk(), "setSharedBufferBase(): remote call failed");
248 }
249 mHeapSizes.removeItem(seqNum);
250 }
251}
252
253status_t CryptoHalHidl::checkSharedBuffer(const ::SharedBuffer& buffer) {
254 int32_t seqNum = static_cast<int32_t>(buffer.bufferId);
255 // memory must be in one of the heaps that have been set
256 if (mHeapSizes.indexOfKey(seqNum) < 0) {
257 return UNKNOWN_ERROR;
258 }
259
260 // memory must be within the address space of the heap
261 size_t heapSize = mHeapSizes.valueFor(seqNum);
262 if (heapSize < buffer.offset + buffer.size || SIZE_MAX - buffer.offset < buffer.size) {
263 android_errorWriteLog(0x534e4554, "76221123");
264 return UNKNOWN_ERROR;
265 }
266
267 return OK;
268}
269
270ssize_t CryptoHalHidl::decrypt(const uint8_t keyId[16], const uint8_t iv[16],
271 CryptoPlugin::Mode mode, const CryptoPlugin::Pattern& pattern,
272 const drm::V1_0::SharedBuffer& hSource, size_t offset,
273 const CryptoPlugin::SubSample* subSamples, size_t numSubSamples,
274 const drm::V1_0::DestinationBuffer& hDestination,
275 AString* errorDetailMsg) {
276 Mutex::Autolock autoLock(mLock);
277
278 if (mInitCheck != OK) {
279 return mInitCheck;
280 }
281
282 Mode hMode;
283 switch (mode) {
284 case CryptoPlugin::kMode_Unencrypted:
285 hMode = Mode::UNENCRYPTED;
286 break;
287 case CryptoPlugin::kMode_AES_CTR:
288 hMode = Mode::AES_CTR;
289 break;
290 case CryptoPlugin::kMode_AES_WV:
291 hMode = Mode::AES_CBC_CTS;
292 break;
293 case CryptoPlugin::kMode_AES_CBC:
294 hMode = Mode::AES_CBC;
295 break;
296 default:
297 return UNKNOWN_ERROR;
298 }
299
300 Pattern hPattern;
301 hPattern.encryptBlocks = pattern.mEncryptBlocks;
302 hPattern.skipBlocks = pattern.mSkipBlocks;
303
304 std::vector<SubSample> stdSubSamples;
305 for (size_t i = 0; i < numSubSamples; i++) {
306 SubSample subSample;
307 subSample.numBytesOfClearData = subSamples[i].mNumBytesOfClearData;
308 subSample.numBytesOfEncryptedData = subSamples[i].mNumBytesOfEncryptedData;
309 stdSubSamples.push_back(subSample);
310 }
311 auto hSubSamples = hidl_vec<SubSample>(stdSubSamples);
312
313 bool secure;
314 if (hDestination.type == BufferType::SHARED_MEMORY) {
315 status_t status = checkSharedBuffer(hDestination.nonsecureMemory);
316 if (status != OK) {
317 return status;
318 }
319 secure = false;
320 } else if (hDestination.type == BufferType::NATIVE_HANDLE) {
321 secure = true;
322 } else {
323 android_errorWriteLog(0x534e4554, "70526702");
324 return UNKNOWN_ERROR;
325 }
326
327 status_t status = checkSharedBuffer(hSource);
328 if (status != OK) {
329 return status;
330 }
331
332 status_t err = UNKNOWN_ERROR;
333 uint32_t bytesWritten = 0;
334
335 Return<void> hResult;
336
337 mLock.unlock();
338 if (mPluginV1_2 != NULL) {
339 hResult = mPluginV1_2->decrypt_1_2(
340 secure, toHidlArray16(keyId), toHidlArray16(iv), hMode, hPattern, hSubSamples,
341 hSource, offset, hDestination,
342 [&](Status_V1_2 status, uint32_t hBytesWritten, hidl_string hDetailedError) {
343 if (status == Status_V1_2::OK) {
344 bytesWritten = hBytesWritten;
Ray Essickca0ee602022-03-09 14:14:58 -0800345 if (errorDetailMsg != nullptr) {
346 *errorDetailMsg = toString8(hDetailedError);
347 }
Kyle Zhang6605add2022-01-13 17:51:23 +0000348 }
349 err = toStatusT(status);
350 });
351 } else {
352 hResult = mPlugin->decrypt(
353 secure, toHidlArray16(keyId), toHidlArray16(iv), hMode, hPattern, hSubSamples,
354 hSource, offset, hDestination,
355 [&](Status status, uint32_t hBytesWritten, hidl_string hDetailedError) {
356 if (status == Status::OK) {
357 bytesWritten = hBytesWritten;
Ray Essickca0ee602022-03-09 14:14:58 -0800358 if (errorDetailMsg != nullptr) {
359 *errorDetailMsg = toString8(hDetailedError);
360 }
Kyle Zhang6605add2022-01-13 17:51:23 +0000361 }
362 err = toStatusT(status);
363 });
364 }
365
366 err = hResult.isOk() ? err : DEAD_OBJECT;
367 if (err == OK) {
368 return bytesWritten;
369 }
370 return err;
371}
372
373void CryptoHalHidl::notifyResolution(uint32_t width, uint32_t height) {
374 Mutex::Autolock autoLock(mLock);
375
376 if (mInitCheck != OK) {
377 return;
378 }
379
380 auto hResult = mPlugin->notifyResolution(width, height);
381 ALOGE_IF(!hResult.isOk(), "notifyResolution txn failed %s", hResult.description().c_str());
382}
383
384status_t CryptoHalHidl::setMediaDrmSession(const Vector<uint8_t>& sessionId) {
385 Mutex::Autolock autoLock(mLock);
386
387 if (mInitCheck != OK) {
388 return mInitCheck;
389 }
390
391 auto err = mPlugin->setMediaDrmSession(toHidlVec(sessionId));
392 return err.isOk() ? toStatusT(err) : DEAD_OBJECT;
393}
394
395status_t CryptoHalHidl::getLogMessages(Vector<drm::V1_4::LogMessage>& logs) const {
396 Mutex::Autolock autoLock(mLock);
397 return DrmUtils::GetLogMessages<drm::V1_4::ICryptoPlugin>(mPlugin, logs);
398}
399} // namespace android