1 /*
2 * Copyright 2022 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 "CryptoAsync"
19
20 #include <log/log.h>
21
22 #include "hidl/HidlSupport.h"
23 #include <media/stagefright/foundation/AMessage.h>
24 #include <media/stagefright/foundation/ABuffer.h>
25 #include <media/stagefright/foundation/ADebug.h>
26
27 #include <media/MediaCodecBuffer.h>
28 #include <media/stagefright/MediaCodec.h>
29 #include <media/stagefright/CryptoAsync.h>
30
31 namespace android {
32
~CryptoAsync()33 CryptoAsync::~CryptoAsync() {
34 }
35
decrypt(sp<AMessage> & msg)36 status_t CryptoAsync::decrypt(sp<AMessage> &msg) {
37 int32_t decryptAction;
38 CHECK(msg->findInt32("action", &decryptAction));
39 if (mCallback == nullptr) {
40 ALOGE("Crypto callback channel is not set");
41 return -ENOSYS;
42 }
43 bool shouldPost = false;
44 Mutexed<std::list<sp<AMessage>>>::Locked pendingBuffers(mPendingBuffers);
45 if (mState != kCryptoAsyncActive) {
46 ALOGE("Cannot decrypt in errored state");
47 return -ENOSYS;
48 }
49 shouldPost = pendingBuffers->size() == 0 ? true : false;
50 pendingBuffers->push_back(std::move(msg));
51 if (shouldPost) {
52 sp<AMessage> decryptMsg = new AMessage(kWhatDecrypt, this);
53 decryptMsg->post();
54 }
55 return OK;
56 }
57
stop(std::list<sp<AMessage>> * const buffers)58 void CryptoAsync::stop(std::list<sp<AMessage>> * const buffers) {
59 sp<AMessage> stopMsg = new AMessage(kWhatStop, this);
60 stopMsg->setPointer("remaining", static_cast<void*>(buffers));
61 sp<AMessage> response;
62 status_t err = stopMsg->postAndAwaitResponse(&response);
63 if (err == OK && response != NULL) {
64 CHECK(response->findInt32("err", &err));
65 } else {
66 ALOGE("Error handling stop in CryptoAsync");
67 //TODO: handle the error here.
68 }
69 }
70
decryptAndQueue(sp<AMessage> & msg)71 status_t CryptoAsync::decryptAndQueue(sp<AMessage> & msg) {
72 std::shared_ptr<BufferChannelBase> channel = mBufferChannel.lock();
73 status_t err = OK;
74 sp<RefBase> obj;
75 size_t numSubSamples = 0;
76 int32_t secure = 0;
77 CryptoPlugin::Mode mode;
78 CryptoPlugin::Pattern pattern;
79 sp<ABuffer> keyBuffer;
80 sp<ABuffer> ivBuffer;
81 sp<ABuffer> subSamplesBuffer;
82 msg->findInt32("encryptBlocks", (int32_t*)&pattern.mEncryptBlocks);
83 msg->findInt32("skipBlocks", (int32_t*)&pattern.mSkipBlocks);
84 msg->findBuffer("key", &keyBuffer);
85 msg->findBuffer("iv", &ivBuffer);
86 msg->findBuffer("subSamples", &subSamplesBuffer);
87 msg->findInt32("secure", &secure);
88 msg->findSize("numSubSamples", &numSubSamples);
89 msg->findObject("buffer", &obj);
90 msg->findInt32("mode", (int32_t*)&mode);
91 AString errorDetailMsg;
92 const uint8_t * key = keyBuffer.get() != nullptr ? keyBuffer.get()->data() : nullptr;
93 const uint8_t * iv = ivBuffer.get() != nullptr ? ivBuffer.get()->data() : nullptr;
94 const CryptoPlugin::SubSample * subSamples =
95 (CryptoPlugin::SubSample *)(subSamplesBuffer.get()->data());
96 sp<MediaCodecBuffer> buffer = static_cast<MediaCodecBuffer *>(obj.get());
97 err = channel->queueSecureInputBuffer(buffer, secure, key, iv, mode,
98 pattern, subSamples, numSubSamples, &errorDetailMsg);
99 if (err != OK) {
100 std::list<sp<AMessage>> errorList;
101 msg->removeEntryByName("buffer");
102 msg->setInt32("err", err);
103 msg->setInt32("actionCode", ACTION_CODE_FATAL);
104 msg->setString("errorDetail", errorDetailMsg);
105 errorList.push_back(std::move(msg));
106 mCallback->onDecryptError(errorList);
107 }
108 return err;
109 }
110
attachEncryptedBufferAndQueue(sp<AMessage> & msg)111 status_t CryptoAsync::attachEncryptedBufferAndQueue(sp<AMessage> & msg) {
112 std::shared_ptr<BufferChannelBase> channel = mBufferChannel.lock();
113 status_t err = OK;
114 sp<RefBase> obj;
115 sp<RefBase> mem_obj;
116 sp<hardware::HidlMemory> memory;
117 size_t numSubSamples = 0;
118 int32_t secure = 0;
119 size_t offset;
120 size_t size;
121 CryptoPlugin::Mode mode;
122 CryptoPlugin::Pattern pattern;
123 sp<ABuffer> keyBuffer;
124 sp<ABuffer> ivBuffer;
125 sp<ABuffer> subSamplesBuffer;
126 msg->findInt32("encryptBlocks", (int32_t*)&pattern.mEncryptBlocks);
127 msg->findInt32("skipBlocks", (int32_t*)&pattern.mSkipBlocks);
128 msg->findBuffer("key", &keyBuffer);
129 msg->findBuffer("iv", &ivBuffer);
130 msg->findBuffer("subSamples", &subSamplesBuffer);
131 msg->findInt32("secure", &secure);
132 msg->findSize("numSubSamples", &numSubSamples);
133 msg->findObject("buffer", &obj);
134 msg->findInt32("mode", (int32_t*)&mode);
135 CHECK(msg->findObject("memory", &mem_obj));
136 CHECK(msg->findSize("offset", (size_t*)&offset));
137 AString errorDetailMsg;
138 // get key info
139 const uint8_t * key = keyBuffer.get() != nullptr ? keyBuffer.get()->data() : nullptr;
140 // get iv info
141 const uint8_t * iv = ivBuffer.get() != nullptr ? ivBuffer.get()->data() : nullptr;
142
143 const CryptoPlugin::SubSample * subSamples =
144 (CryptoPlugin::SubSample *)(subSamplesBuffer.get()->data());
145
146 // get MediaCodecBuffer
147 sp<MediaCodecBuffer> buffer = static_cast<MediaCodecBuffer *>(obj.get());
148
149 // get HidlMemory
150 memory = static_cast<MediaCodec::WrapperObject<sp<hardware::HidlMemory>> *>
151 (mem_obj.get())->value;
152
153 // attach buffer
154 err = channel->attachEncryptedBuffer(
155 memory, secure, key, iv, mode, pattern,
156 offset, subSamples, numSubSamples, buffer, &errorDetailMsg);
157
158 // a generic error
159 auto handleError = [this, &err, &msg]() {
160 std::list<sp<AMessage>> errorList;
161 msg->removeEntryByName("buffer");
162 msg->setInt32("err", err);
163 msg->setInt32("actionCode", ACTION_CODE_FATAL);
164 errorList.push_back(std::move(msg));
165 mCallback->onDecryptError(errorList);
166 };
167 if (err != OK) {
168 handleError();
169 return err;
170 }
171 offset = buffer->offset();
172 size = buffer->size();
173
174 if (offset + size > buffer->capacity()) {
175 err = -ENOSYS;
176 handleError();
177 return err;
178 }
179 buffer->setRange(offset, size);
180 err = channel->queueInputBuffer(buffer);
181 if (err != OK) {
182 handleError();
183 return err;
184 }
185 return err;
186 }
187
onMessageReceived(const sp<AMessage> & msg)188 void CryptoAsync::onMessageReceived(const sp<AMessage> & msg) {
189 status_t err = OK;
190 auto getCurrentAndNextTask =
191 [this](sp<AMessage> * const current, uint32_t & nextTask) -> status_t {
192 sp<AMessage> obj;
193 Mutexed<std::list<sp<AMessage>>>::Locked pendingBuffers(mPendingBuffers);
194 if ((pendingBuffers->size() == 0) || (mState != kCryptoAsyncActive)) {
195 return -ENOMSG;
196 }
197 *current = std::move(*(pendingBuffers->begin()));
198 pendingBuffers->pop_front();
199 //Try to see if we will be able to process next buffer
200 while((nextTask == kWhatDoNothing) && pendingBuffers->size() > 0)
201 {
202 sp<AMessage> & nextBuffer = pendingBuffers->front();
203 if (nextBuffer == nullptr) {
204 pendingBuffers->pop_front();
205 continue;
206 }
207 nextTask = kWhatDecrypt;
208 }
209 return OK;
210 };
211 switch(msg->what()) {
212 case kWhatDecrypt:
213 {
214 sp<AMessage> thisMsg;
215 uint32_t nextTask = kWhatDoNothing;
216 if(OK != getCurrentAndNextTask(&thisMsg, nextTask)) {
217 return;
218 }
219 if (thisMsg != nullptr) {
220 int32_t action;
221 err = OK;
222 CHECK(thisMsg->findInt32("action", &action));
223 switch(action) {
224 case kActionDecrypt:
225 {
226 err = decryptAndQueue(thisMsg);
227 break;
228 }
229
230 case kActionAttachEncryptedBuffer:
231 {
232 err = attachEncryptedBufferAndQueue(thisMsg);
233 break;
234 }
235
236 default:
237 {
238 ALOGE("Unrecognized action in decrypt");
239 }
240 }
241 if (err != OK) {
242 Mutexed<std::list<sp<AMessage>>>::Locked pendingBuffers(mPendingBuffers);
243 mState = kCryptoAsyncError;
244 }
245 }
246 // we won't take next buffers if buffer caused
247 // an error. We want the caller to deal with the error first
248 // Expected behahiour is that the caller acknowledge the error
249 // with a call to stop() which clear the queues.
250 // Then move forward with processing of next set of buffers.
251 if (mState == kCryptoAsyncActive && nextTask != kWhatDoNothing) {
252 sp<AMessage> nextMsg = new AMessage(nextTask,this);
253 nextMsg->post();
254 }
255 break;
256 }
257
258 case kWhatStop:
259 {
260 typedef std::list<sp<AMessage>> ReturnListType;
261 ReturnListType * returnList = nullptr;
262 sp<AReplyToken> replyID;
263 CHECK(msg->senderAwaitsResponse(&replyID));
264 sp<AMessage> response = new AMessage;
265 msg->findPointer("remaining", (void**)(&returnList));
266 Mutexed<std::list<sp<AMessage>>>::Locked pendingBuffers(mPendingBuffers);
267 if (returnList) {
268 returnList->clear();
269 returnList->splice(returnList->end(), std::move(*pendingBuffers));
270 }
271 pendingBuffers->clear();
272 mState = kCryptoAsyncActive;
273 response->setInt32("err", OK);
274 response->postReply(replyID);
275
276 break;
277 }
278
279 default:
280 {
281 status_t err = OK;
282 //TODO: do something with error here.
283 (void)err;
284 break;
285 }
286 }
287 }
288
289 } // namespace android
290