1 /*
2 * Copyright (C) 2018 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 "Codec2Client"
19 #include <log/log.h>
20
21 #include <codec2/hidl/client.h>
22
23 #include <deque>
24 #include <limits>
25 #include <map>
26 #include <type_traits>
27 #include <vector>
28
29 #include <bufferpool/ClientManager.h>
30 #include <cutils/properties.h>
31 #include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
32 #include <hidl/HidlSupport.h>
33 #include <media/stagefright/bqhelper/WGraphicBufferProducer.h>
34 #undef LOG
35
36 #include <android/hardware/media/bufferpool/1.0/IClientManager.h>
37 #include <hardware/google/media/c2/1.0/IComponent.h>
38 #include <hardware/google/media/c2/1.0/IComponentInterface.h>
39 #include <hardware/google/media/c2/1.0/IComponentListener.h>
40 #include <hardware/google/media/c2/1.0/IComponentStore.h>
41 #include <hardware/google/media/c2/1.0/IConfigurable.h>
42
43 #include <C2Debug.h>
44 #include <C2BufferPriv.h>
45 #include <C2PlatformSupport.h>
46
47 namespace android {
48
49 using ::android::hardware::hidl_vec;
50 using ::android::hardware::hidl_string;
51 using ::android::hardware::Return;
52 using ::android::hardware::Void;
53 using ::android::TWGraphicBufferProducer;
54
55 using namespace ::hardware::google::media::c2::V1_0;
56 using namespace ::hardware::google::media::c2::V1_0::utils;
57 using namespace ::android::hardware::media::bufferpool::V1_0;
58 using namespace ::android::hardware::media::bufferpool::V1_0::implementation;
59
60 namespace /* unnamed */ {
61
62 // c2_status_t value that corresponds to hwbinder transaction failure.
63 constexpr c2_status_t C2_TRANSACTION_FAILED = C2_CORRUPTED;
64
65 // List of known IComponentStore services.
66 constexpr const char* kClientNames[] = {
67 "default",
68 "software",
69 };
70
71 typedef std::array<
72 std::shared_ptr<Codec2Client>,
73 std::extent<decltype(kClientNames)>::value> ClientList;
74
75 // Convenience methods to obtain known clients.
getClientCount()76 size_t getClientCount() {
77 // TODO: this may not work if there is no default service
78 return std::extent<decltype(kClientNames)>::value;
79 }
80
getClient(size_t index)81 std::shared_ptr<Codec2Client> getClient(size_t index) {
82 return Codec2Client::CreateFromService(kClientNames[index]);
83 }
84
getClientList()85 ClientList getClientList() {
86 ClientList list;
87 for (size_t i = 0; i < list.size(); ++i) {
88 list[i] = getClient(i);
89 }
90 return list;
91 }
92
93 } // unnamed
94
95 // Codec2ConfigurableClient
96
getName() const97 const C2String& Codec2ConfigurableClient::getName() const {
98 return mName;
99 }
100
base() const101 Codec2ConfigurableClient::Base* Codec2ConfigurableClient::base() const {
102 return static_cast<Base*>(mBase.get());
103 }
104
Codec2ConfigurableClient(const sp<Codec2ConfigurableClient::Base> & base)105 Codec2ConfigurableClient::Codec2ConfigurableClient(
106 const sp<Codec2ConfigurableClient::Base>& base) : mBase(base) {
107 Return<void> transStatus = base->getName(
108 [this](const hidl_string& name) {
109 mName = name.c_str();
110 });
111 if (!transStatus.isOk()) {
112 ALOGE("Cannot obtain name from IConfigurable.");
113 }
114 }
115
query(const std::vector<C2Param * > & stackParams,const std::vector<C2Param::Index> & heapParamIndices,c2_blocking_t mayBlock,std::vector<std::unique_ptr<C2Param>> * const heapParams) const116 c2_status_t Codec2ConfigurableClient::query(
117 const std::vector<C2Param*> &stackParams,
118 const std::vector<C2Param::Index> &heapParamIndices,
119 c2_blocking_t mayBlock,
120 std::vector<std::unique_ptr<C2Param>>* const heapParams) const {
121 hidl_vec<ParamIndex> indices(
122 stackParams.size() + heapParamIndices.size());
123 size_t numIndices = 0;
124 for (C2Param* const& stackParam : stackParams) {
125 if (!stackParam) {
126 ALOGW("query -- null stack param encountered.");
127 continue;
128 }
129 indices[numIndices++] = static_cast<ParamIndex>(stackParam->index());
130 }
131 size_t numStackIndices = numIndices;
132 for (const C2Param::Index& index : heapParamIndices) {
133 indices[numIndices++] =
134 static_cast<ParamIndex>(static_cast<uint32_t>(index));
135 }
136 indices.resize(numIndices);
137 if (heapParams) {
138 heapParams->reserve(heapParams->size() + numIndices);
139 }
140 c2_status_t status;
141 Return<void> transStatus = base()->query(
142 indices,
143 mayBlock == C2_MAY_BLOCK,
144 [&status, &numStackIndices, &stackParams, heapParams](
145 Status s, const Params& p) {
146 status = static_cast<c2_status_t>(s);
147 if (status != C2_OK && status != C2_BAD_INDEX) {
148 ALOGE("query -- call failed. "
149 "Error code = %d", static_cast<int>(status));
150 return;
151 }
152 std::vector<C2Param*> paramPointers;
153 c2_status_t parseStatus = parseParamsBlob(¶mPointers, p);
154 if (parseStatus != C2_OK) {
155 ALOGE("query -- error while parsing params. "
156 "Error code = %d", static_cast<int>(status));
157 status = parseStatus;
158 return;
159 }
160 size_t i = 0;
161 for (auto it = paramPointers.begin(); it != paramPointers.end(); ) {
162 C2Param* paramPointer = *it;
163 if (numStackIndices > 0) {
164 --numStackIndices;
165 if (!paramPointer) {
166 ALOGW("query -- null stack param.");
167 ++it;
168 continue;
169 }
170 for (; i < stackParams.size() && !stackParams[i]; ) {
171 ++i;
172 }
173 if (i >= stackParams.size()) {
174 ALOGE("query -- unexpected error.");
175 status = C2_CORRUPTED;
176 return;
177 }
178 if (stackParams[i]->index() != paramPointer->index()) {
179 ALOGW("query -- param skipped. index = %d",
180 static_cast<int>(stackParams[i]->index()));
181 stackParams[i++]->invalidate();
182 continue;
183 }
184 if (!stackParams[i++]->updateFrom(*paramPointer)) {
185 ALOGW("query -- param update failed. index = %d",
186 static_cast<int>(paramPointer->index()));
187 }
188 } else {
189 if (!paramPointer) {
190 ALOGW("query -- null heap param.");
191 ++it;
192 continue;
193 }
194 if (!heapParams) {
195 ALOGW("query -- extra stack param.");
196 }
197 heapParams->emplace_back(C2Param::Copy(*paramPointer));
198 }
199 ++it;
200 }
201 });
202 if (!transStatus.isOk()) {
203 ALOGE("query -- transaction failed.");
204 return C2_TRANSACTION_FAILED;
205 }
206 return status;
207 }
208
config(const std::vector<C2Param * > & params,c2_blocking_t mayBlock,std::vector<std::unique_ptr<C2SettingResult>> * const failures)209 c2_status_t Codec2ConfigurableClient::config(
210 const std::vector<C2Param*> ¶ms,
211 c2_blocking_t mayBlock,
212 std::vector<std::unique_ptr<C2SettingResult>>* const failures) {
213 Params hidlParams;
214 Status hidlStatus = createParamsBlob(&hidlParams, params);
215 if (hidlStatus != Status::OK) {
216 ALOGE("config -- bad input.");
217 return C2_TRANSACTION_FAILED;
218 }
219 c2_status_t status;
220 Return<void> transStatus = base()->config(
221 hidlParams,
222 mayBlock == C2_MAY_BLOCK,
223 [&status, ¶ms, failures](
224 Status s,
225 const hidl_vec<SettingResult> f,
226 const Params& o) {
227 status = static_cast<c2_status_t>(s);
228 if (status != C2_OK) {
229 ALOGD("config -- call failed. "
230 "Error code = %d", static_cast<int>(status));
231 }
232 size_t i = failures->size();
233 failures->resize(i + f.size());
234 for (const SettingResult& sf : f) {
235 status = objcpy(&(*failures)[i++], sf);
236 if (status != C2_OK) {
237 ALOGE("config -- invalid returned SettingResult. "
238 "Error code = %d", static_cast<int>(status));
239 return;
240 }
241 }
242 status = updateParamsFromBlob(params, o);
243 });
244 if (!transStatus.isOk()) {
245 ALOGE("config -- transaction failed.");
246 return C2_TRANSACTION_FAILED;
247 }
248 return status;
249 }
250
querySupportedParams(std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const251 c2_status_t Codec2ConfigurableClient::querySupportedParams(
252 std::vector<std::shared_ptr<C2ParamDescriptor>>* const params) const {
253 // TODO: Cache and query properly!
254 c2_status_t status;
255 Return<void> transStatus = base()->querySupportedParams(
256 std::numeric_limits<uint32_t>::min(),
257 std::numeric_limits<uint32_t>::max(),
258 [&status, params](
259 Status s,
260 const hidl_vec<ParamDescriptor>& p) {
261 status = static_cast<c2_status_t>(s);
262 if (status != C2_OK) {
263 ALOGE("querySupportedParams -- call failed. "
264 "Error code = %d", static_cast<int>(status));
265 return;
266 }
267 size_t i = params->size();
268 params->resize(i + p.size());
269 for (const ParamDescriptor& sp : p) {
270 status = objcpy(&(*params)[i++], sp);
271 if (status != C2_OK) {
272 ALOGE("querySupportedParams -- "
273 "invalid returned ParamDescriptor. "
274 "Error code = %d", static_cast<int>(status));
275 return;
276 }
277 }
278 });
279 if (!transStatus.isOk()) {
280 ALOGE("querySupportedParams -- transaction failed.");
281 return C2_TRANSACTION_FAILED;
282 }
283 return status;
284 }
285
querySupportedValues(std::vector<C2FieldSupportedValuesQuery> & fields,c2_blocking_t mayBlock) const286 c2_status_t Codec2ConfigurableClient::querySupportedValues(
287 std::vector<C2FieldSupportedValuesQuery>& fields,
288 c2_blocking_t mayBlock) const {
289 hidl_vec<FieldSupportedValuesQuery> inFields(fields.size());
290 for (size_t i = 0; i < fields.size(); ++i) {
291 Status hidlStatus = objcpy(&inFields[i], fields[i]);
292 if (hidlStatus != Status::OK) {
293 ALOGE("querySupportedValues -- bad input");
294 return C2_TRANSACTION_FAILED;
295 }
296 }
297
298 c2_status_t status;
299 Return<void> transStatus = base()->querySupportedValues(
300 inFields,
301 mayBlock == C2_MAY_BLOCK,
302 [&status, &inFields, &fields](
303 Status s,
304 const hidl_vec<FieldSupportedValuesQueryResult>& r) {
305 status = static_cast<c2_status_t>(s);
306 if (status != C2_OK) {
307 ALOGE("querySupportedValues -- call failed. "
308 "Error code = %d", static_cast<int>(status));
309 return;
310 }
311 if (r.size() != fields.size()) {
312 ALOGE("querySupportedValues -- input and output lists "
313 "have different sizes.");
314 status = C2_CORRUPTED;
315 return;
316 }
317 for (size_t i = 0; i < fields.size(); ++i) {
318 status = objcpy(&fields[i], inFields[i], r[i]);
319 if (status != C2_OK) {
320 ALOGE("querySupportedValues -- invalid returned value. "
321 "Error code = %d", static_cast<int>(status));
322 return;
323 }
324 }
325 });
326 if (!transStatus.isOk()) {
327 ALOGE("querySupportedValues -- transaction failed.");
328 return C2_TRANSACTION_FAILED;
329 }
330 return status;
331 }
332
333 // Codec2Client
334
base() const335 Codec2Client::Base* Codec2Client::base() const {
336 return static_cast<Base*>(mBase.get());
337 }
338
Codec2Client(const sp<Codec2Client::Base> & base,std::string instanceName)339 Codec2Client::Codec2Client(const sp<Codec2Client::Base>& base, std::string instanceName) :
340 Codec2ConfigurableClient(base), mListed(false), mInstanceName(instanceName) {
341 Return<sp<IClientManager>> transResult = base->getPoolClientManager();
342 if (!transResult.isOk()) {
343 ALOGE("getPoolClientManager -- failed transaction.");
344 } else {
345 mHostPoolManager = static_cast<sp<IClientManager>>(transResult);
346 }
347 }
348
createComponent(const C2String & name,const std::shared_ptr<Codec2Client::Listener> & listener,std::shared_ptr<Codec2Client::Component> * const component)349 c2_status_t Codec2Client::createComponent(
350 const C2String& name,
351 const std::shared_ptr<Codec2Client::Listener>& listener,
352 std::shared_ptr<Codec2Client::Component>* const component) {
353
354 // TODO: Add support for Bufferpool
355
356 struct HidlListener : public IComponentListener {
357 std::weak_ptr<Component> component;
358 std::weak_ptr<Listener> base;
359
360 virtual Return<void> onWorkDone(const WorkBundle& workBundle) override {
361 std::list<std::unique_ptr<C2Work>> workItems;
362 c2_status_t status = objcpy(&workItems, workBundle);
363 if (status != C2_OK) {
364 ALOGE("onWorkDone -- received corrupted WorkBundle. "
365 "status = %d.", static_cast<int>(status));
366 return Void();
367 }
368 // release input buffers potentially held by the component from queue
369 std::shared_ptr<Codec2Client::Component> strongComponent = component.lock();
370 if (strongComponent) {
371 strongComponent->handleOnWorkDone(workItems);
372 }
373 if (std::shared_ptr<Codec2Client::Listener> listener = base.lock()) {
374 listener->onWorkDone(component, workItems);
375 } else {
376 ALOGW("onWorkDone -- listener died.");
377 }
378 return Void();
379 }
380
381 virtual Return<void> onTripped(
382 const hidl_vec<SettingResult>& settingResults) override {
383 std::vector<std::shared_ptr<C2SettingResult>> c2SettingResults(
384 settingResults.size());
385 c2_status_t status;
386 for (size_t i = 0; i < settingResults.size(); ++i) {
387 std::unique_ptr<C2SettingResult> c2SettingResult;
388 status = objcpy(&c2SettingResult, settingResults[i]);
389 if (status != C2_OK) {
390 ALOGE("onTripped -- received corrupted SettingResult. "
391 "status = %d.", static_cast<int>(status));
392 return Void();
393 }
394 c2SettingResults[i] = std::move(c2SettingResult);
395 }
396 if (std::shared_ptr<Codec2Client::Listener> listener = base.lock()) {
397 listener->onTripped(component, c2SettingResults);
398 } else {
399 ALOGW("onTripped -- listener died.");
400 }
401 return Void();
402 }
403
404 virtual Return<void> onError(Status s, uint32_t errorCode) override {
405 ALOGE("onError -- status = %d, errorCode = %u.",
406 static_cast<int>(s),
407 static_cast<unsigned>(errorCode));
408 if (std::shared_ptr<Listener> listener = base.lock()) {
409 listener->onError(component, s == Status::OK ?
410 errorCode : static_cast<c2_status_t>(s));
411 } else {
412 ALOGW("onError -- listener died.");
413 }
414 return Void();
415 }
416
417 virtual Return<void> onFramesRendered(
418 const hidl_vec<RenderedFrame>& renderedFrames) override {
419 if (std::shared_ptr<Listener> listener = base.lock()) {
420 std::vector<Codec2Client::Listener::RenderedFrame>
421 rfs(renderedFrames.size());
422 for (size_t i = 0; i < rfs.size(); ++i) {
423 rfs[i].bufferQueueId = static_cast<uint64_t>(
424 renderedFrames[i].bufferQueueId);
425 rfs[i].slotId = static_cast<int32_t>(
426 renderedFrames[i].slotId);
427 rfs[i].timestampNs = static_cast<int64_t>(
428 renderedFrames[i].timestampNs);
429 }
430 listener->onFramesRendered(rfs);
431 } else {
432 ALOGW("onFramesRendered -- listener died.");
433 }
434 return Void();
435 }
436
437 };
438
439 c2_status_t status;
440 sp<HidlListener> hidlListener = new HidlListener();
441 hidlListener->base = listener;
442 Return<void> transStatus = base()->createComponent(
443 name,
444 hidlListener,
445 ClientManager::getInstance(),
446 [&status, component, hidlListener](
447 Status s,
448 const sp<IComponent>& c) {
449 status = static_cast<c2_status_t>(s);
450 if (status != C2_OK) {
451 return;
452 }
453 *component = std::make_shared<Codec2Client::Component>(c);
454 hidlListener->component = *component;
455 });
456 if (!transStatus.isOk()) {
457 ALOGE("createComponent -- failed transaction.");
458 return C2_TRANSACTION_FAILED;
459 }
460
461 if (status != C2_OK) {
462 return status;
463 }
464
465 if (!*component) {
466 ALOGE("createComponent -- null component.");
467 return C2_CORRUPTED;
468 }
469
470 status = (*component)->setDeathListener(*component, listener);
471 if (status != C2_OK) {
472 ALOGE("createComponent -- setDeathListener returned error: %d.",
473 static_cast<int>(status));
474 }
475
476 (*component)->mBufferPoolSender.setReceiver(mHostPoolManager);
477 return status;
478 }
479
createInterface(const C2String & name,std::shared_ptr<Codec2Client::Interface> * const interface)480 c2_status_t Codec2Client::createInterface(
481 const C2String& name,
482 std::shared_ptr<Codec2Client::Interface>* const interface) {
483 c2_status_t status;
484 Return<void> transStatus = base()->createInterface(
485 name,
486 [&status, interface](
487 Status s,
488 const sp<IComponentInterface>& i) {
489 status = static_cast<c2_status_t>(s);
490 if (status != C2_OK) {
491 ALOGE("createInterface -- call failed. "
492 "Error code = %d", static_cast<int>(status));
493 return;
494 }
495 *interface = std::make_shared<Codec2Client::Interface>(i);
496 });
497 if (!transStatus.isOk()) {
498 ALOGE("createInterface -- failed transaction.");
499 return C2_TRANSACTION_FAILED;
500 }
501 return status;
502 }
503
createInputSurface(std::shared_ptr<Codec2Client::InputSurface> * const inputSurface)504 c2_status_t Codec2Client::createInputSurface(
505 std::shared_ptr<Codec2Client::InputSurface>* const inputSurface) {
506 Return<sp<IInputSurface>> transResult = base()->createInputSurface();
507 if (!transResult.isOk()) {
508 ALOGE("createInputSurface -- failed transaction.");
509 return C2_TRANSACTION_FAILED;
510 }
511 *inputSurface = std::make_shared<InputSurface>(
512 static_cast<sp<IInputSurface>>(transResult));
513 if (!*inputSurface) {
514 ALOGE("createInputSurface -- failed to create client.");
515 return C2_CORRUPTED;
516 }
517 return C2_OK;
518 }
519
listComponents() const520 const std::vector<C2Component::Traits>& Codec2Client::listComponents() const {
521 std::lock_guard<std::mutex> lock(mMutex);
522 if (mListed) {
523 return mTraitsList;
524 }
525 Return<void> transStatus = base()->listComponents(
526 [this](const hidl_vec<IComponentStore::ComponentTraits>& t) {
527 mTraitsList.resize(t.size());
528 mAliasesBuffer.resize(t.size());
529 for (size_t i = 0; i < t.size(); ++i) {
530 c2_status_t status = objcpy(
531 &mTraitsList[i], &mAliasesBuffer[i], t[i]);
532 if (status != C2_OK) {
533 ALOGE("listComponents -- corrupted output.");
534 return;
535 }
536 }
537 });
538 if (!transStatus.isOk()) {
539 ALOGE("listComponents -- failed transaction.");
540 }
541 mListed = true;
542 return mTraitsList;
543 }
544
copyBuffer(const std::shared_ptr<C2Buffer> & src,const std::shared_ptr<C2Buffer> & dst)545 c2_status_t Codec2Client::copyBuffer(
546 const std::shared_ptr<C2Buffer>& src,
547 const std::shared_ptr<C2Buffer>& dst) {
548 // TODO: Implement?
549 (void)src;
550 (void)dst;
551 ALOGE("copyBuffer not implemented");
552 return C2_OMITTED;
553 }
554
555 std::shared_ptr<C2ParamReflector>
getParamReflector()556 Codec2Client::getParamReflector() {
557 // TODO: this is not meant to be exposed as C2ParamReflector on the client side; instead, it
558 // should reflect the HAL API.
559 struct SimpleParamReflector : public C2ParamReflector {
560 virtual std::unique_ptr<C2StructDescriptor> describe(C2Param::CoreIndex coreIndex) const {
561 hidl_vec<ParamIndex> indices(1);
562 indices[0] = static_cast<ParamIndex>(coreIndex.coreIndex());
563 std::unique_ptr<C2StructDescriptor> descriptor;
564 Return<void> transStatus = mBase->getStructDescriptors(
565 indices,
566 [&descriptor](
567 Status s,
568 const hidl_vec<StructDescriptor>& sd) {
569 c2_status_t status = static_cast<c2_status_t>(s);
570 if (status != C2_OK) {
571 ALOGE("getStructDescriptors -- call failed. "
572 "Error code = %d", static_cast<int>(status));
573 descriptor.reset();
574 return;
575 }
576 if (sd.size() != 1) {
577 ALOGD("getStructDescriptors -- returned vector of size %zu.",
578 sd.size());
579 descriptor.reset();
580 return;
581 }
582 status = objcpy(&descriptor, sd[0]);
583 if (status != C2_OK) {
584 ALOGD("getStructDescriptors -- failed to convert. "
585 "Error code = %d", static_cast<int>(status));
586 descriptor.reset();
587 return;
588 }
589 });
590 return descriptor;
591 }
592
593 SimpleParamReflector(sp<Base> base)
594 : mBase(base) { }
595
596 sp<Base> mBase;
597 };
598
599 return std::make_shared<SimpleParamReflector>(base());
600 };
601
CreateFromService(const char * instanceName,bool waitForService)602 std::shared_ptr<Codec2Client> Codec2Client::CreateFromService(
603 const char* instanceName, bool waitForService) {
604 if (!instanceName) {
605 return nullptr;
606 }
607 sp<Base> baseStore = waitForService ?
608 Base::getService(instanceName) :
609 Base::tryGetService(instanceName);
610 if (!baseStore) {
611 if (waitForService) {
612 ALOGE("Codec2.0 service inaccessible. Check the device manifest.");
613 } else {
614 ALOGW("Codec2.0 service not available right now. Try again later.");
615 }
616 return nullptr;
617 }
618 return std::make_shared<Codec2Client>(baseStore, instanceName);
619 }
620
ForAllStores(const std::string & key,std::function<c2_status_t (const std::shared_ptr<Codec2Client> &)> predicate)621 c2_status_t Codec2Client::ForAllStores(
622 const std::string &key,
623 std::function<c2_status_t(const std::shared_ptr<Codec2Client>&)> predicate) {
624 c2_status_t status = C2_NO_INIT; // no IComponentStores present
625
626 // Cache the mapping key -> index of Codec2Client in getClient().
627 static std::mutex key2IndexMutex;
628 static std::map<std::string, size_t> key2Index;
629
630 // By default try all stores. However, try the last known client first. If the last known
631 // client fails, retry once. We do this by pushing the last known client in front of the
632 // list of all clients.
633 std::deque<size_t> indices;
634 for (size_t index = getClientCount(); index > 0; ) {
635 indices.push_front(--index);
636 }
637
638 bool wasMapped = false;
639 std::unique_lock<std::mutex> lock(key2IndexMutex);
640 auto it = key2Index.find(key);
641 if (it != key2Index.end()) {
642 indices.push_front(it->second);
643 wasMapped = true;
644 }
645 lock.unlock();
646
647 for (size_t index : indices) {
648 std::shared_ptr<Codec2Client> client = getClient(index);
649 if (client) {
650 status = predicate(client);
651 if (status == C2_OK) {
652 lock.lock();
653 key2Index[key] = index; // update last known client index
654 return status;
655 }
656 }
657 if (wasMapped) {
658 ALOGI("Could not find '%s' in last instance. Retrying...", key.c_str());
659 wasMapped = false;
660 }
661 }
662 return status; // return the last status from a valid client
663 }
664
665 std::shared_ptr<Codec2Client::Component>
CreateComponentByName(const char * componentName,const std::shared_ptr<Listener> & listener,std::shared_ptr<Codec2Client> * owner)666 Codec2Client::CreateComponentByName(
667 const char* componentName,
668 const std::shared_ptr<Listener>& listener,
669 std::shared_ptr<Codec2Client>* owner) {
670 std::shared_ptr<Component> component;
671 c2_status_t status = ForAllStores(
672 componentName,
673 [owner, &component, componentName, &listener](
674 const std::shared_ptr<Codec2Client> &client) -> c2_status_t {
675 c2_status_t status = client->createComponent(componentName, listener, &component);
676 if (status == C2_OK) {
677 if (owner) {
678 *owner = client;
679 }
680 } else if (status != C2_NOT_FOUND) {
681 ALOGD("IComponentStore(%s)::createComponent('%s') returned %s",
682 client->getInstanceName().c_str(), componentName, asString(status));
683 }
684 return status;
685 });
686 if (status != C2_OK) {
687 ALOGI("Could not create component '%s' (%s)", componentName, asString(status));
688 }
689 return component;
690 }
691
692 std::shared_ptr<Codec2Client::Interface>
CreateInterfaceByName(const char * interfaceName,std::shared_ptr<Codec2Client> * owner)693 Codec2Client::CreateInterfaceByName(
694 const char* interfaceName,
695 std::shared_ptr<Codec2Client>* owner) {
696 std::shared_ptr<Interface> interface;
697 c2_status_t status = ForAllStores(
698 interfaceName,
699 [owner, &interface, interfaceName](
700 const std::shared_ptr<Codec2Client> &client) -> c2_status_t {
701 c2_status_t status = client->createInterface(interfaceName, &interface);
702 if (status == C2_OK) {
703 if (owner) {
704 *owner = client;
705 }
706 } else if (status != C2_NOT_FOUND) {
707 ALOGD("IComponentStore(%s)::createInterface('%s') returned %s",
708 client->getInstanceName().c_str(), interfaceName, asString(status));
709 }
710 return status;
711 });
712 if (status != C2_OK) {
713 ALOGI("Could not create interface '%s' (%s)", interfaceName, asString(status));
714 }
715 return interface;
716 }
717
ListComponents()718 const std::vector<C2Component::Traits>& Codec2Client::ListComponents() {
719 static std::vector<C2Component::Traits> traitsList = [](){
720 std::vector<C2Component::Traits> list;
721 size_t listSize = 0;
722 ClientList clientList = getClientList();
723 for (const std::shared_ptr<Codec2Client>& client : clientList) {
724 if (!client) {
725 continue;
726 }
727 listSize += client->listComponents().size();
728 }
729 list.reserve(listSize);
730 for (const std::shared_ptr<Codec2Client>& client : clientList) {
731 if (!client) {
732 continue;
733 }
734 list.insert(
735 list.end(),
736 client->listComponents().begin(),
737 client->listComponents().end());
738 }
739 return list;
740 }();
741
742 return traitsList;
743 }
744
745 // Codec2Client::Listener
746
~Listener()747 Codec2Client::Listener::~Listener() {
748 }
749
750 // Codec2Client::Component
751
base() const752 Codec2Client::Component::Base* Codec2Client::Component::base() const {
753 return static_cast<Base*>(mBase.get());
754 }
755
Component(const sp<Codec2Client::Component::Base> & base)756 Codec2Client::Component::Component(const sp<Codec2Client::Component::Base>& base) :
757 Codec2Client::Configurable(base),
758 mBufferPoolSender(nullptr) {
759 }
760
~Component()761 Codec2Client::Component::~Component() {
762 }
763
createBlockPool(C2Allocator::id_t id,C2BlockPool::local_id_t * blockPoolId,std::shared_ptr<Codec2Client::Configurable> * configurable)764 c2_status_t Codec2Client::Component::createBlockPool(
765 C2Allocator::id_t id,
766 C2BlockPool::local_id_t* blockPoolId,
767 std::shared_ptr<Codec2Client::Configurable>* configurable) {
768 c2_status_t status;
769 Return<void> transStatus = base()->createBlockPool(
770 static_cast<uint32_t>(id),
771 [&status, blockPoolId, configurable](
772 Status s,
773 uint64_t pId,
774 const sp<IConfigurable>& c) {
775 status = static_cast<c2_status_t>(s);
776 configurable->reset();
777 if (status != C2_OK) {
778 ALOGE("createBlockPool -- call failed. "
779 "Error code = %d", static_cast<int>(status));
780 return;
781 }
782 *blockPoolId = static_cast<C2BlockPool::local_id_t>(pId);
783 *configurable = std::make_shared<Codec2Client::Configurable>(c);
784 });
785 if (!transStatus.isOk()) {
786 ALOGE("createBlockPool -- transaction failed.");
787 return C2_TRANSACTION_FAILED;
788 }
789 return status;
790 }
791
destroyBlockPool(C2BlockPool::local_id_t localId)792 c2_status_t Codec2Client::Component::destroyBlockPool(
793 C2BlockPool::local_id_t localId) {
794 Return<Status> transResult = base()->destroyBlockPool(
795 static_cast<uint64_t>(localId));
796 if (!transResult.isOk()) {
797 ALOGE("destroyBlockPool -- transaction failed.");
798 return C2_TRANSACTION_FAILED;
799 }
800 return static_cast<c2_status_t>(static_cast<Status>(transResult));
801 }
802
handleOnWorkDone(const std::list<std::unique_ptr<C2Work>> & workItems)803 void Codec2Client::Component::handleOnWorkDone(
804 const std::list<std::unique_ptr<C2Work>> &workItems) {
805 // Input buffers' lifetime management
806 std::vector<uint64_t> inputDone;
807 for (const std::unique_ptr<C2Work> &work : workItems) {
808 if (work) {
809 inputDone.emplace_back(work->input.ordinal.frameIndex.peeku());
810 }
811 }
812
813 {
814 std::lock_guard<std::mutex> lock(mInputBuffersMutex);
815 for (uint64_t inputIndex : inputDone) {
816 auto it = mInputBuffers.find(inputIndex);
817 if (it == mInputBuffers.end()) {
818 ALOGI("unknown input index %llu in onWorkDone", (long long)inputIndex);
819 } else {
820 ALOGV("done with input index %llu with %zu buffers",
821 (long long)inputIndex, it->second.size());
822 mInputBuffers.erase(it);
823 }
824 }
825 }
826
827 // Output bufferqueue-based blocks' lifetime management
828 mOutputBufferQueueMutex.lock();
829 sp<IGraphicBufferProducer> igbp = mOutputIgbp;
830 uint64_t bqId = mOutputBqId;
831 uint32_t generation = mOutputGeneration;
832 mOutputBufferQueueMutex.unlock();
833
834 if (igbp) {
835 holdBufferQueueBlocks(workItems, igbp, bqId, generation);
836 }
837 }
838
queue(std::list<std::unique_ptr<C2Work>> * const items)839 c2_status_t Codec2Client::Component::queue(
840 std::list<std::unique_ptr<C2Work>>* const items) {
841 // remember input buffers queued to hold reference to them
842 {
843 std::lock_guard<std::mutex> lock(mInputBuffersMutex);
844 for (const std::unique_ptr<C2Work> &work : *items) {
845 if (!work) {
846 continue;
847 }
848
849 uint64_t inputIndex = work->input.ordinal.frameIndex.peeku();
850 auto res = mInputBuffers.emplace(inputIndex, work->input.buffers);
851 if (!res.second) {
852 ALOGI("duplicate input index %llu in queue", (long long)inputIndex);
853 // TODO: append? - for now we are replacing
854 res.first->second = work->input.buffers;
855 }
856 ALOGV("qeueing input index %llu with %zu buffers",
857 (long long)inputIndex, work->input.buffers.size());
858 }
859 }
860
861 WorkBundle workBundle;
862 Status hidlStatus = objcpy(&workBundle, *items, &mBufferPoolSender);
863 if (hidlStatus != Status::OK) {
864 ALOGE("queue -- bad input.");
865 return C2_TRANSACTION_FAILED;
866 }
867 Return<Status> transStatus = base()->queue(workBundle);
868 if (!transStatus.isOk()) {
869 ALOGE("queue -- transaction failed.");
870 return C2_TRANSACTION_FAILED;
871 }
872 c2_status_t status =
873 static_cast<c2_status_t>(static_cast<Status>(transStatus));
874 if (status != C2_OK) {
875 ALOGE("queue -- call failed. "
876 "Error code = %d", static_cast<int>(status));
877 }
878 return status;
879 }
880
flush(C2Component::flush_mode_t mode,std::list<std::unique_ptr<C2Work>> * const flushedWork)881 c2_status_t Codec2Client::Component::flush(
882 C2Component::flush_mode_t mode,
883 std::list<std::unique_ptr<C2Work>>* const flushedWork) {
884 (void)mode; // Flush mode isn't supported in HIDL yet.
885 c2_status_t status;
886 Return<void> transStatus = base()->flush(
887 [&status, flushedWork](
888 Status s, const WorkBundle& wb) {
889 status = static_cast<c2_status_t>(s);
890 if (status != C2_OK) {
891 ALOGE("flush -- call failed. "
892 "Error code = %d", static_cast<int>(status));
893 return;
894 }
895 status = objcpy(flushedWork, wb);
896 });
897 if (!transStatus.isOk()) {
898 ALOGE("flush -- transaction failed.");
899 return C2_TRANSACTION_FAILED;
900 }
901
902 // Indices of flushed work items.
903 std::vector<uint64_t> flushedIndices;
904 for (const std::unique_ptr<C2Work> &work : *flushedWork) {
905 if (work) {
906 flushedIndices.emplace_back(work->input.ordinal.frameIndex.peeku());
907 }
908 }
909
910 // Input buffers' lifetime management
911 for (uint64_t flushedIndex : flushedIndices) {
912 std::lock_guard<std::mutex> lock(mInputBuffersMutex);
913 auto it = mInputBuffers.find(flushedIndex);
914 if (it == mInputBuffers.end()) {
915 ALOGI("unknown input index %llu in flush", (long long)flushedIndex);
916 } else {
917 ALOGV("flushed input index %llu with %zu buffers",
918 (long long)flushedIndex, it->second.size());
919 mInputBuffers.erase(it);
920 }
921 }
922
923 // Output bufferqueue-based blocks' lifetime management
924 mOutputBufferQueueMutex.lock();
925 sp<IGraphicBufferProducer> igbp = mOutputIgbp;
926 uint64_t bqId = mOutputBqId;
927 uint32_t generation = mOutputGeneration;
928 mOutputBufferQueueMutex.unlock();
929
930 if (igbp) {
931 holdBufferQueueBlocks(*flushedWork, igbp, bqId, generation);
932 }
933
934 return status;
935 }
936
drain(C2Component::drain_mode_t mode)937 c2_status_t Codec2Client::Component::drain(C2Component::drain_mode_t mode) {
938 Return<Status> transStatus = base()->drain(
939 mode == C2Component::DRAIN_COMPONENT_WITH_EOS);
940 if (!transStatus.isOk()) {
941 ALOGE("drain -- transaction failed.");
942 return C2_TRANSACTION_FAILED;
943 }
944 c2_status_t status =
945 static_cast<c2_status_t>(static_cast<Status>(transStatus));
946 if (status != C2_OK) {
947 ALOGE("drain -- call failed. "
948 "Error code = %d", static_cast<int>(status));
949 }
950 return status;
951 }
952
start()953 c2_status_t Codec2Client::Component::start() {
954 Return<Status> transStatus = base()->start();
955 if (!transStatus.isOk()) {
956 ALOGE("start -- transaction failed.");
957 return C2_TRANSACTION_FAILED;
958 }
959 c2_status_t status =
960 static_cast<c2_status_t>(static_cast<Status>(transStatus));
961 if (status != C2_OK) {
962 ALOGE("start -- call failed. "
963 "Error code = %d", static_cast<int>(status));
964 }
965 return status;
966 }
967
stop()968 c2_status_t Codec2Client::Component::stop() {
969 Return<Status> transStatus = base()->stop();
970 if (!transStatus.isOk()) {
971 ALOGE("stop -- transaction failed.");
972 return C2_TRANSACTION_FAILED;
973 }
974 c2_status_t status =
975 static_cast<c2_status_t>(static_cast<Status>(transStatus));
976 if (status != C2_OK) {
977 ALOGE("stop -- call failed. "
978 "Error code = %d", static_cast<int>(status));
979 }
980 mInputBuffersMutex.lock();
981 mInputBuffers.clear();
982 mInputBuffersMutex.unlock();
983 return status;
984 }
985
reset()986 c2_status_t Codec2Client::Component::reset() {
987 Return<Status> transStatus = base()->reset();
988 if (!transStatus.isOk()) {
989 ALOGE("reset -- transaction failed.");
990 return C2_TRANSACTION_FAILED;
991 }
992 c2_status_t status =
993 static_cast<c2_status_t>(static_cast<Status>(transStatus));
994 if (status != C2_OK) {
995 ALOGE("reset -- call failed. "
996 "Error code = %d", static_cast<int>(status));
997 }
998 mInputBuffersMutex.lock();
999 mInputBuffers.clear();
1000 mInputBuffersMutex.unlock();
1001 return status;
1002 }
1003
release()1004 c2_status_t Codec2Client::Component::release() {
1005 Return<Status> transStatus = base()->release();
1006 if (!transStatus.isOk()) {
1007 ALOGE("release -- transaction failed.");
1008 return C2_TRANSACTION_FAILED;
1009 }
1010 c2_status_t status =
1011 static_cast<c2_status_t>(static_cast<Status>(transStatus));
1012 if (status != C2_OK) {
1013 ALOGE("release -- call failed. "
1014 "Error code = %d", static_cast<int>(status));
1015 }
1016 mInputBuffersMutex.lock();
1017 mInputBuffers.clear();
1018 mInputBuffersMutex.unlock();
1019 return status;
1020 }
1021
setOutputSurface(C2BlockPool::local_id_t blockPoolId,const sp<IGraphicBufferProducer> & surface,uint32_t generation)1022 c2_status_t Codec2Client::Component::setOutputSurface(
1023 C2BlockPool::local_id_t blockPoolId,
1024 const sp<IGraphicBufferProducer>& surface,
1025 uint32_t generation) {
1026 sp<HGraphicBufferProducer> igbp = surface->getHalInterface();
1027 if (!igbp) {
1028 igbp = new TWGraphicBufferProducer<HGraphicBufferProducer>(surface);
1029 }
1030
1031 Return<Status> transStatus = base()->setOutputSurface(
1032 static_cast<uint64_t>(blockPoolId), igbp);
1033 if (!transStatus.isOk()) {
1034 ALOGE("setOutputSurface -- transaction failed.");
1035 return C2_TRANSACTION_FAILED;
1036 }
1037 c2_status_t status =
1038 static_cast<c2_status_t>(static_cast<Status>(transStatus));
1039 if (status != C2_OK) {
1040 ALOGE("setOutputSurface -- call failed. "
1041 "Error code = %d", static_cast<int>(status));
1042 } else {
1043 std::lock_guard<std::mutex> lock(mOutputBufferQueueMutex);
1044 if (mOutputIgbp != surface) {
1045 mOutputIgbp = surface;
1046 if (!surface) {
1047 mOutputBqId = 0;
1048 } else if (surface->getUniqueId(&mOutputBqId) != OK) {
1049 ALOGE("setOutputSurface -- cannot obtain bufferqueue id.");
1050 }
1051 }
1052 mOutputGeneration = generation;
1053 }
1054 return status;
1055 }
1056
queueToOutputSurface(const C2ConstGraphicBlock & block,const QueueBufferInput & input,QueueBufferOutput * output)1057 status_t Codec2Client::Component::queueToOutputSurface(
1058 const C2ConstGraphicBlock& block,
1059 const QueueBufferInput& input,
1060 QueueBufferOutput* output) {
1061 uint64_t bqId;
1062 int32_t bqSlot;
1063 if (!getBufferQueueAssignment(block, &bqId, &bqSlot) || bqId == 0) {
1064 // Block not from bufferqueue -- it must be attached before queuing.
1065
1066 mOutputBufferQueueMutex.lock();
1067 sp<IGraphicBufferProducer> outputIgbp = mOutputIgbp;
1068 uint32_t outputGeneration = mOutputGeneration;
1069 mOutputBufferQueueMutex.unlock();
1070
1071 status_t status = !attachToBufferQueue(block,
1072 outputIgbp,
1073 outputGeneration,
1074 &bqSlot);
1075 if (status != OK) {
1076 ALOGW("queueToOutputSurface -- attaching failed.");
1077 return INVALID_OPERATION;
1078 }
1079
1080 status = outputIgbp->queueBuffer(static_cast<int>(bqSlot),
1081 input, output);
1082 if (status != OK) {
1083 ALOGE("queueToOutputSurface -- queueBuffer() failed "
1084 "on non-bufferqueue-based block. "
1085 "Error code = %d.",
1086 static_cast<int>(status));
1087 return status;
1088 }
1089 return OK;
1090 }
1091
1092 mOutputBufferQueueMutex.lock();
1093 sp<IGraphicBufferProducer> outputIgbp = mOutputIgbp;
1094 uint64_t outputBqId = mOutputBqId;
1095 mOutputBufferQueueMutex.unlock();
1096
1097 if (!outputIgbp) {
1098 ALOGE("queueToOutputSurface -- output surface is null.");
1099 return NO_INIT;
1100 }
1101
1102 if (bqId != outputBqId) {
1103 ALOGE("queueToOutputSurface -- bufferqueue ids mismatch.");
1104 return DEAD_OBJECT;
1105 }
1106
1107 status_t status = outputIgbp->queueBuffer(static_cast<int>(bqSlot),
1108 input, output);
1109 if (status != OK) {
1110 ALOGE("queueToOutputSurface -- queueBuffer() failed "
1111 "on bufferqueue-based block. "
1112 "Error code = %d.",
1113 static_cast<int>(status));
1114 return status;
1115 }
1116 if (!yieldBufferQueueBlock(block)) {
1117 ALOGE("queueToOutputSurface -- cannot yield bufferqueue-based block "
1118 "to the bufferqueue.");
1119 return UNKNOWN_ERROR;
1120 }
1121 return OK;
1122 }
1123
connectToOmxInputSurface(const sp<HGraphicBufferProducer> & producer,const sp<HGraphicBufferSource> & source)1124 c2_status_t Codec2Client::Component::connectToOmxInputSurface(
1125 const sp<HGraphicBufferProducer>& producer,
1126 const sp<HGraphicBufferSource>& source) {
1127 Return<Status> transStatus = base()->connectToOmxInputSurface(
1128 producer, source);
1129 if (!transStatus.isOk()) {
1130 ALOGE("connectToOmxInputSurface -- transaction failed.");
1131 return C2_TRANSACTION_FAILED;
1132 }
1133 c2_status_t status =
1134 static_cast<c2_status_t>(static_cast<Status>(transStatus));
1135 if (status != C2_OK) {
1136 ALOGE("connectToOmxInputSurface -- call failed. "
1137 "Error code = %d", static_cast<int>(status));
1138 }
1139 return status;
1140 }
1141
disconnectFromInputSurface()1142 c2_status_t Codec2Client::Component::disconnectFromInputSurface() {
1143 Return<Status> transStatus = base()->disconnectFromInputSurface();
1144 if (!transStatus.isOk()) {
1145 ALOGE("disconnectToInputSurface -- transaction failed.");
1146 return C2_TRANSACTION_FAILED;
1147 }
1148 c2_status_t status =
1149 static_cast<c2_status_t>(static_cast<Status>(transStatus));
1150 if (status != C2_OK) {
1151 ALOGE("disconnectFromInputSurface -- call failed. "
1152 "Error code = %d", static_cast<int>(status));
1153 }
1154 return status;
1155 }
1156
setDeathListener(const std::shared_ptr<Component> & component,const std::shared_ptr<Listener> & listener)1157 c2_status_t Codec2Client::Component::setDeathListener(
1158 const std::shared_ptr<Component>& component,
1159 const std::shared_ptr<Listener>& listener) {
1160
1161 struct HidlDeathRecipient : public hardware::hidl_death_recipient {
1162 std::weak_ptr<Component> component;
1163 std::weak_ptr<Listener> base;
1164
1165 virtual void serviceDied(
1166 uint64_t /* cookie */,
1167 const wp<::android::hidl::base::V1_0::IBase>& /* who */
1168 ) override {
1169 if (std::shared_ptr<Codec2Client::Listener> listener = base.lock()) {
1170 listener->onDeath(component);
1171 } else {
1172 ALOGW("onDeath -- listener died.");
1173 }
1174 }
1175 };
1176
1177 sp<HidlDeathRecipient> deathRecipient = new HidlDeathRecipient();
1178 deathRecipient->base = listener;
1179 deathRecipient->component = component;
1180
1181 component->mDeathRecipient = deathRecipient;
1182 Return<bool> transResult = component->base()->linkToDeath(
1183 component->mDeathRecipient, 0);
1184 if (!transResult.isOk()) {
1185 ALOGE("setDeathListener -- failed transaction: linkToDeath.");
1186 return C2_TRANSACTION_FAILED;
1187 }
1188 if (!static_cast<bool>(transResult)) {
1189 ALOGE("setDeathListener -- linkToDeath call failed.");
1190 return C2_CORRUPTED;
1191 }
1192 return C2_OK;
1193 }
1194
1195 // Codec2Client::InputSurface
1196
base() const1197 Codec2Client::InputSurface::Base* Codec2Client::InputSurface::base() const {
1198 return static_cast<Base*>(mBase.get());
1199 }
1200
InputSurface(const sp<IInputSurface> & base)1201 Codec2Client::InputSurface::InputSurface(const sp<IInputSurface>& base) :
1202 mBase(base),
1203 mGraphicBufferProducer(new
1204 ::android::hardware::graphics::bufferqueue::V1_0::utils::
1205 H2BGraphicBufferProducer(base)) {
1206 }
1207
connectToComponent(const std::shared_ptr<Codec2Client::Component> & component,std::shared_ptr<Connection> * connection)1208 c2_status_t Codec2Client::InputSurface::connectToComponent(
1209 const std::shared_ptr<Codec2Client::Component>& component,
1210 std::shared_ptr<Connection>* connection) {
1211 c2_status_t status;
1212 Return<void> transStatus = base()->connectToComponent(
1213 component->base(),
1214 [&status, connection](
1215 Status s,
1216 const sp<IInputSurfaceConnection>& c) {
1217 status = static_cast<c2_status_t>(s);
1218 if (status != C2_OK) {
1219 ALOGE("connectToComponent -- call failed. "
1220 "Error code = %d", static_cast<int>(status));
1221 return;
1222 }
1223 *connection = std::make_shared<Connection>(c);
1224 });
1225 if (!transStatus.isOk()) {
1226 ALOGE("connect -- transaction failed.");
1227 return C2_TRANSACTION_FAILED;
1228 }
1229 return status;
1230 }
1231
1232 std::shared_ptr<Codec2Client::Configurable>
getConfigurable() const1233 Codec2Client::InputSurface::getConfigurable() const {
1234 Return<sp<IConfigurable>> transResult = base()->getConfigurable();
1235 if (!transResult.isOk()) {
1236 ALOGW("getConfigurable -- transaction failed.");
1237 return nullptr;
1238 }
1239 if (!static_cast<sp<IConfigurable>>(transResult)) {
1240 ALOGW("getConfigurable -- null pointer.");
1241 return nullptr;
1242 }
1243 return std::make_shared<Configurable>(transResult);
1244 }
1245
1246 const sp<IGraphicBufferProducer>&
getGraphicBufferProducer() const1247 Codec2Client::InputSurface::getGraphicBufferProducer() const {
1248 return mGraphicBufferProducer;
1249 }
1250
1251 // Codec2Client::InputSurfaceConnection
1252
1253 Codec2Client::InputSurfaceConnection::Base*
base() const1254 Codec2Client::InputSurfaceConnection::base() const {
1255 return static_cast<Base*>(mBase.get());
1256 }
1257
InputSurfaceConnection(const sp<Codec2Client::InputSurfaceConnection::Base> & base)1258 Codec2Client::InputSurfaceConnection::InputSurfaceConnection(
1259 const sp<Codec2Client::InputSurfaceConnection::Base>& base) :
1260 mBase(base) {
1261 }
1262
disconnect()1263 c2_status_t Codec2Client::InputSurfaceConnection::disconnect() {
1264 Return<Status> transResult = base()->disconnect();
1265 return static_cast<c2_status_t>(static_cast<Status>(transResult));
1266 }
1267
1268 } // namespace android
1269
1270