1 /*
2 * Copyright 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 #define ATRACE_TAG ATRACE_TAG_VIDEO
20 #include <android-base/logging.h>
21 #include <utils/Trace.h>
22
23 #include <android_media_codec.h>
24
25 #include <codec2/aidl/GraphicBufferAllocator.h>
26 #include <codec2/common/HalSelection.h>
27 #include <codec2/hidl/client.h>
28
29 #include <C2Debug.h>
30 #include <C2BufferPriv.h>
31 #include <C2Config.h> // for C2StreamUsageTuning
32 #include <C2PlatformSupport.h>
33
34 #include <android/hardware/media/bufferpool/2.0/IClientManager.h>
35 #include <android/hardware/media/c2/1.0/IComponent.h>
36 #include <android/hardware/media/c2/1.0/IComponentInterface.h>
37 #include <android/hardware/media/c2/1.0/IComponentListener.h>
38 #include <android/hardware/media/c2/1.0/IComponentStore.h>
39 #include <android/hardware/media/c2/1.0/IConfigurable.h>
40 #include <android/hidl/manager/1.2/IServiceManager.h>
41
42 #include <aidl/android/hardware/media/bufferpool2/IClientManager.h>
43 #include <aidl/android/hardware/media/c2/BnComponentListener.h>
44 #include <aidl/android/hardware/media/c2/FieldSupportedValues.h>
45 #include <aidl/android/hardware/media/c2/FieldSupportedValuesQuery.h>
46 #include <aidl/android/hardware/media/c2/FieldSupportedValuesQueryResult.h>
47 #include <aidl/android/hardware/media/c2/IComponent.h>
48 #include <aidl/android/hardware/media/c2/IComponentInterface.h>
49 #include <aidl/android/hardware/media/c2/IComponentStore.h>
50 #include <aidl/android/hardware/media/c2/IConfigurable.h>
51 #include <aidl/android/hardware/media/c2/ParamDescriptor.h>
52 #include <aidl/android/hardware/media/c2/StructDescriptor.h>
53
54 #include <aidlcommonsupport/NativeHandle.h>
55 #include <android/api-level.h>
56 #include <android/binder_auto_utils.h>
57 #include <android/binder_ibinder.h>
58 #include <android/binder_manager.h>
59 #include <android-base/properties.h>
60 #include <android-base/scopeguard.h>
61 #include <android-base/stringprintf.h>
62 #include <apex/ApexCodecs.h>
63 #include <bufferpool/ClientManager.h>
64 #include <bufferpool2/ClientManager.h>
65 #include <codec2/aidl/BufferTypes.h>
66 #include <codec2/aidl/ParamTypes.h>
67 #include <codec2/hidl/1.0/types.h>
68 #include <codec2/hidl/1.1/types.h>
69 #include <codec2/hidl/1.2/types.h>
70 #include <codec2/hidl/output.h>
71 #include <cutils/native_handle.h>
72 #include <gui/bufferqueue/2.0/B2HGraphicBufferProducer.h>
73 #include <gui/bufferqueue/2.0/H2BGraphicBufferProducer.h>
74 #include <hardware/gralloc.h> // for GRALLOC_USAGE_*
75 #include <hidl/HidlSupport.h>
76 #include <media/stagefright/foundation/ADebug.h> // for asString(status_t)
77 #include <private/android/AHardwareBufferHelpers.h>
78 #include <system/window.h> // for NATIVE_WINDOW_QUERY_*
79
80 #include <algorithm>
81 #include <deque>
82 #include <iterator>
83 #include <limits>
84 #include <map>
85 #include <mutex>
86 #include <optional>
87 #include <ranges>
88 #include <sstream>
89 #include <thread>
90 #include <type_traits>
91 #include <vector>
92
93 namespace android {
94
95 using ::android::hardware::hidl_vec;
96 using ::android::hardware::hidl_string;
97 using ::android::hardware::Return;
98 using ::android::hardware::Void;
99
100 using HGraphicBufferProducer1 = ::android::hardware::graphics::bufferqueue::
101 V1_0::IGraphicBufferProducer;
102 using HGraphicBufferProducer2 = ::android::hardware::graphics::bufferqueue::
103 V2_0::IGraphicBufferProducer;
104 using B2HGraphicBufferProducer2 = ::android::hardware::graphics::bufferqueue::
105 V2_0::utils::B2HGraphicBufferProducer;
106 using H2BGraphicBufferProducer2 = ::android::hardware::graphics::bufferqueue::
107 V2_0::utils::H2BGraphicBufferProducer;
108 using ::android::hardware::media::c2::V1_2::SurfaceSyncObj;
109
110 using AidlGraphicBufferAllocator = ::aidl::android::hardware::media::c2::
111 implementation::GraphicBufferAllocator;
112
113 namespace bufferpool2_aidl = ::aidl::android::hardware::media::bufferpool2;
114 namespace bufferpool_hidl = ::android::hardware::media::bufferpool::V2_0;
115 namespace c2_aidl = ::aidl::android::hardware::media::c2;
116 namespace c2_hidl_base = ::android::hardware::media::c2;
117 namespace c2_hidl = ::android::hardware::media::c2::V1_2;
118
119 using c2_hidl::utils::operator<<;
120
121 namespace /* unnamed */ {
122
123 // c2_status_t value that corresponds to hwbinder transaction failure.
124 constexpr c2_status_t C2_TRANSACTION_FAILED = C2_CORRUPTED;
125
126 // By default prepare buffer to be displayed on any of the common surfaces
127 constexpr uint64_t kDefaultConsumerUsage =
128 (GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_COMPOSER);
129
130 // Searches for a name in GetServiceNames() and returns the index found. If the
131 // name is not found, the returned index will be equal to
132 // GetServiceNames().size().
getServiceIndex(char const * name)133 size_t getServiceIndex(char const* name) {
134 std::vector<std::string> const& names = Codec2Client::GetServiceNames();
135 size_t i = 0;
136 for (; i < names.size(); ++i) {
137 if (name == names[i]) {
138 break;
139 }
140 }
141 return i;
142 }
143
144 class Client2Store : public C2ComponentStore {
145 std::shared_ptr<Codec2Client> mClient;
146
147 public:
Client2Store(std::shared_ptr<Codec2Client> const & client)148 Client2Store(std::shared_ptr<Codec2Client> const& client)
149 : mClient(client) { }
150
151 virtual ~Client2Store() = default;
152
config_sm(std::vector<C2Param * > const & params,std::vector<std::unique_ptr<C2SettingResult>> * const failures)153 virtual c2_status_t config_sm(
154 std::vector<C2Param*> const ¶ms,
155 std::vector<std::unique_ptr<C2SettingResult>>* const failures) {
156 return mClient->config(params, C2_MAY_BLOCK, failures);
157 };
158
copyBuffer(std::shared_ptr<C2GraphicBuffer>,std::shared_ptr<C2GraphicBuffer>)159 virtual c2_status_t copyBuffer(
160 std::shared_ptr<C2GraphicBuffer>,
161 std::shared_ptr<C2GraphicBuffer>) {
162 return C2_OMITTED;
163 }
164
createComponent(C2String,std::shared_ptr<C2Component> * const component)165 virtual c2_status_t createComponent(
166 C2String, std::shared_ptr<C2Component>* const component) {
167 component->reset();
168 return C2_OMITTED;
169 }
170
createInterface(C2String,std::shared_ptr<C2ComponentInterface> * const interface)171 virtual c2_status_t createInterface(
172 C2String, std::shared_ptr<C2ComponentInterface>* const interface) {
173 interface->reset();
174 return C2_OMITTED;
175 }
176
query_sm(std::vector<C2Param * > const & stackParams,std::vector<C2Param::Index> const & heapParamIndices,std::vector<std::unique_ptr<C2Param>> * const heapParams) const177 virtual c2_status_t query_sm(
178 std::vector<C2Param*> const& stackParams,
179 std::vector<C2Param::Index> const& heapParamIndices,
180 std::vector<std::unique_ptr<C2Param>>* const heapParams) const {
181 return mClient->query(stackParams, heapParamIndices, C2_MAY_BLOCK, heapParams);
182 }
183
querySupportedParams_nb(std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const184 virtual c2_status_t querySupportedParams_nb(
185 std::vector<std::shared_ptr<C2ParamDescriptor>>* const params) const {
186 return mClient->querySupportedParams(params);
187 }
188
querySupportedValues_sm(std::vector<C2FieldSupportedValuesQuery> & fields) const189 virtual c2_status_t querySupportedValues_sm(
190 std::vector<C2FieldSupportedValuesQuery>& fields) const {
191 return mClient->querySupportedValues(fields, C2_MAY_BLOCK);
192 }
193
getName() const194 virtual C2String getName() const {
195 return mClient->getName();
196 }
197
getParamReflector() const198 virtual std::shared_ptr<C2ParamReflector> getParamReflector() const {
199 return mClient->getParamReflector();
200 }
201
listComponents()202 virtual std::vector<std::shared_ptr<C2Component::Traits const>> listComponents() {
203 return std::vector<std::shared_ptr<C2Component::Traits const>>();
204 }
205 };
206
GetC2Status(const::ndk::ScopedAStatus & transStatus,const char * method)207 c2_status_t GetC2Status(const ::ndk::ScopedAStatus &transStatus, const char *method) {
208 if (!transStatus.isOk()) {
209 if (transStatus.getExceptionCode() == EX_SERVICE_SPECIFIC) {
210 c2_status_t status = static_cast<c2_status_t>(transStatus.getServiceSpecificError());
211 LOG(DEBUG) << method << " -- call failed: " << status << ".";
212 return status;
213 } else {
214 LOG(ERROR) << method << " -- transaction failed.";
215 return C2_TRANSACTION_FAILED;
216 }
217 }
218 return C2_OK;
219 }
220
221 } // unnamed namespace
222
223 // This class caches a Codec2Client object and its component traits. The client
224 // will be created the first time it is needed, and it can be refreshed if the
225 // service dies (by calling invalidate()). The first time listComponents() is
226 // called from the client, the result will be cached.
227 class Codec2Client::Cache {
228 // Cached client
229 std::shared_ptr<Codec2Client> mClient;
230 mutable std::mutex mClientMutex;
231
232 // Cached component traits
233 std::vector<C2Component::Traits> mTraits;
234 std::once_flag mTraitsInitializationFlag;
235
236 // The index of the service. This is based on GetServiceNames().
237 size_t mIndex;
238 // Called by s() exactly once to initialize the cache. The index must be a
239 // valid index into the vector returned by GetServiceNames(). Calling
240 // init(index) will associate the cache to the service with name
241 // GetServiceNames()[index].
init(size_t index)242 void init(size_t index) {
243 mIndex = index;
244 }
245
246 public:
247 Cache() = default;
248
249 // Initializes mClient if needed, then returns mClient.
250 // If the service is unavailable but listed in the manifest, this function
251 // will block indefinitely.
getClient()252 std::shared_ptr<Codec2Client> getClient() {
253 std::scoped_lock lock{mClientMutex};
254 if (!mClient) {
255 mClient = Codec2Client::_CreateFromIndex(mIndex);
256 }
257 CHECK(mClient) << "Failed to create Codec2Client to service \""
258 << GetServiceNames()[mIndex] << "\". (Index = "
259 << mIndex << ").";
260 return mClient;
261 }
262
263 // Causes a subsequent call to getClient() to create a new client. This
264 // function should be called after the service dies.
265 //
266 // Note: This function is called only by ForAllServices().
invalidate()267 void invalidate() {
268 std::scoped_lock lock{mClientMutex};
269 mClient = nullptr;
270 }
271
272 // Returns a list of traits for components supported by the service. This
273 // list is cached.
getTraits()274 std::vector<C2Component::Traits> const& getTraits() {
275 std::call_once(mTraitsInitializationFlag, [this]() {
276 bool success{false};
277 // Spin until _listComponents() is successful.
278 while (true) {
279 std::shared_ptr<Codec2Client> client = getClient();
280 mTraits = client->_listComponents(&success);
281 if (success) {
282 break;
283 }
284 invalidate();
285 using namespace std::chrono_literals;
286 static constexpr auto kServiceRetryPeriod = 5s;
287 LOG(INFO) << "Failed to retrieve component traits from service "
288 "\"" << GetServiceNames()[mIndex] << "\". "
289 "Retrying...";
290 std::this_thread::sleep_for(kServiceRetryPeriod);
291 }
292 });
293 return mTraits;
294 }
295
296 // List() returns the list of all caches.
List()297 static std::vector<Cache>& List() {
298 static std::vector<Cache> sCaches{[]() {
299 size_t numServices = GetServiceNames().size();
300 std::vector<Cache> caches(numServices);
301 for (size_t i = 0; i < numServices; ++i) {
302 caches[i].init(i);
303 }
304 return caches;
305 }()};
306 return sCaches;
307 }
308 };
309 // Codec2ConfigurableClient::HidlImpl
310
311 struct Codec2ConfigurableClient::HidlImpl : public Codec2ConfigurableClient::ImplBase {
312 typedef c2_hidl::IConfigurable Base;
313
314 // base cannot be null.
315 explicit HidlImpl(const sp<Base>& base);
316
getNameandroid::Codec2ConfigurableClient::HidlImpl317 const C2String& getName() const override {
318 return mName;
319 }
320
321 c2_status_t query(
322 const std::vector<C2Param*>& stackParams,
323 const std::vector<C2Param::Index> &heapParamIndices,
324 c2_blocking_t mayBlock,
325 std::vector<std::unique_ptr<C2Param>>* const heapParams) const override;
326
327 c2_status_t config(
328 const std::vector<C2Param*> ¶ms,
329 c2_blocking_t mayBlock,
330 std::vector<std::unique_ptr<C2SettingResult>>* const failures) override;
331
332 c2_status_t querySupportedParams(
333 std::vector<std::shared_ptr<C2ParamDescriptor>>* const params
334 ) const override;
335
336 c2_status_t querySupportedValues(
337 std::vector<C2FieldSupportedValuesQuery>& fields,
338 c2_blocking_t mayBlock) const override;
339
340 private:
341 sp<Base> mBase;
342 const C2String mName;
343 };
344
HidlImpl(const sp<Base> & base)345 Codec2ConfigurableClient::HidlImpl::HidlImpl(const sp<Base>& base)
346 : mBase{base},
__anon926bcd9b0402() 347 mName{[base]() -> C2String {
348 C2String outName;
349 Return<void> transStatus = base->getName(
350 [&outName](const hidl_string& name) {
351 outName = name.c_str();
352 });
353 return transStatus.isOk() ? outName : "";
354 }()} {
355 }
356
query(const std::vector<C2Param * > & stackParams,const std::vector<C2Param::Index> & heapParamIndices,c2_blocking_t mayBlock,std::vector<std::unique_ptr<C2Param>> * const heapParams) const357 c2_status_t Codec2ConfigurableClient::HidlImpl::query(
358 const std::vector<C2Param*> &stackParams,
359 const std::vector<C2Param::Index> &heapParamIndices,
360 c2_blocking_t mayBlock,
361 std::vector<std::unique_ptr<C2Param>>* const heapParams) const {
362 hidl_vec<c2_hidl::ParamIndex> indices(
363 stackParams.size() + heapParamIndices.size());
364 size_t numIndices = 0;
365 for (C2Param* const& stackParam : stackParams) {
366 if (!stackParam) {
367 LOG(WARNING) << "query -- null stack param encountered.";
368 continue;
369 }
370 indices[numIndices++] = static_cast<c2_hidl::ParamIndex>(stackParam->index());
371 }
372 size_t numStackIndices = numIndices;
373 for (const C2Param::Index& index : heapParamIndices) {
374 indices[numIndices++] =
375 static_cast<c2_hidl::ParamIndex>(static_cast<uint32_t>(index));
376 }
377 indices.resize(numIndices);
378 if (heapParams) {
379 heapParams->reserve(heapParams->size() + numIndices);
380 }
381 c2_status_t status;
382 Return<void> transStatus = mBase->query(
383 indices,
384 mayBlock == C2_MAY_BLOCK,
385 [&status, &numStackIndices, &stackParams, heapParams](
386 c2_hidl::Status s, const c2_hidl::Params& p) {
387 status = static_cast<c2_status_t>(s);
388 if (status != C2_OK && status != C2_BAD_INDEX) {
389 LOG(DEBUG) << "query -- call failed: "
390 << status << ".";
391 return;
392 }
393 std::vector<C2Param*> paramPointers;
394 if (!c2_hidl::utils::parseParamsBlob(¶mPointers, p)) {
395 LOG(ERROR) << "query -- error while parsing params.";
396 status = C2_CORRUPTED;
397 return;
398 }
399 size_t i = 0;
400 for (auto it = paramPointers.begin();
401 it != paramPointers.end(); ) {
402 C2Param* paramPointer = *it;
403 if (numStackIndices > 0) {
404 --numStackIndices;
405 if (!paramPointer) {
406 LOG(WARNING) << "query -- null stack param.";
407 ++it;
408 continue;
409 }
410 for (; i < stackParams.size() && !stackParams[i]; ) {
411 ++i;
412 }
413 if (i >= stackParams.size()) {
414 LOG(ERROR) << "query -- unexpected error.";
415 status = C2_CORRUPTED;
416 return;
417 }
418 if (stackParams[i]->index() != paramPointer->index()) {
419 LOG(WARNING) << "query -- param skipped: "
420 "index = "
421 << stackParams[i]->index() << ".";
422 stackParams[i++]->invalidate();
423 continue;
424 }
425 if (!stackParams[i++]->updateFrom(*paramPointer)) {
426 LOG(WARNING) << "query -- param update failed: "
427 "index = "
428 << paramPointer->index() << ".";
429 }
430 } else {
431 if (!paramPointer) {
432 LOG(WARNING) << "query -- null heap param.";
433 ++it;
434 continue;
435 }
436 if (!heapParams) {
437 LOG(WARNING) << "query -- "
438 "unexpected extra stack param.";
439 } else {
440 heapParams->emplace_back(
441 C2Param::Copy(*paramPointer));
442 }
443 }
444 ++it;
445 }
446 });
447 if (!transStatus.isOk()) {
448 LOG(ERROR) << "query -- transaction failed.";
449 return C2_TRANSACTION_FAILED;
450 }
451 return status;
452 }
453
config(const std::vector<C2Param * > & params,c2_blocking_t mayBlock,std::vector<std::unique_ptr<C2SettingResult>> * const failures)454 c2_status_t Codec2ConfigurableClient::HidlImpl::config(
455 const std::vector<C2Param*> ¶ms,
456 c2_blocking_t mayBlock,
457 std::vector<std::unique_ptr<C2SettingResult>>* const failures) {
458 c2_hidl::Params hidlParams;
459 if (!c2_hidl::utils::createParamsBlob(&hidlParams, params)) {
460 LOG(ERROR) << "config -- bad input.";
461 return C2_TRANSACTION_FAILED;
462 }
463 c2_status_t status;
464 Return<void> transStatus = mBase->config(
465 hidlParams,
466 mayBlock == C2_MAY_BLOCK,
467 [&status, ¶ms, failures](
468 c2_hidl::Status s,
469 const hidl_vec<c2_hidl::SettingResult> f,
470 const c2_hidl::Params& o) {
471 status = static_cast<c2_status_t>(s);
472 if (status != C2_OK && status != C2_BAD_INDEX) {
473 LOG(DEBUG) << "config -- call failed: "
474 << status << ".";
475 }
476 size_t i = failures->size();
477 failures->resize(i + f.size());
478 for (const c2_hidl::SettingResult& sf : f) {
479 if (!c2_hidl::utils::objcpy(&(*failures)[i++], sf)) {
480 LOG(ERROR) << "config -- "
481 << "invalid SettingResult returned.";
482 return;
483 }
484 }
485 if (!c2_hidl::utils::updateParamsFromBlob(params, o)) {
486 LOG(ERROR) << "config -- "
487 << "failed to parse returned params.";
488 status = C2_CORRUPTED;
489 }
490 });
491 if (!transStatus.isOk()) {
492 LOG(ERROR) << "config -- transaction failed.";
493 return C2_TRANSACTION_FAILED;
494 }
495 return status;
496 }
497
querySupportedParams(std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const498 c2_status_t Codec2ConfigurableClient::HidlImpl::querySupportedParams(
499 std::vector<std::shared_ptr<C2ParamDescriptor>>* const params) const {
500 // TODO: Cache and query properly!
501 c2_status_t status;
502 Return<void> transStatus = mBase->querySupportedParams(
503 std::numeric_limits<uint32_t>::min(),
504 std::numeric_limits<uint32_t>::max(),
505 [&status, params](
506 c2_hidl::Status s,
507 const hidl_vec<c2_hidl::ParamDescriptor>& p) {
508 status = static_cast<c2_status_t>(s);
509 if (status != C2_OK) {
510 LOG(DEBUG) << "querySupportedParams -- call failed: "
511 << status << ".";
512 return;
513 }
514 size_t i = params->size();
515 params->resize(i + p.size());
516 for (const c2_hidl::ParamDescriptor& sp : p) {
517 if (!c2_hidl::utils::objcpy(&(*params)[i++], sp)) {
518 LOG(ERROR) << "querySupportedParams -- "
519 << "invalid returned ParamDescriptor.";
520 return;
521 }
522 }
523 });
524 if (!transStatus.isOk()) {
525 LOG(ERROR) << "querySupportedParams -- transaction failed.";
526 return C2_TRANSACTION_FAILED;
527 }
528 return status;
529 }
530
querySupportedValues(std::vector<C2FieldSupportedValuesQuery> & fields,c2_blocking_t mayBlock) const531 c2_status_t Codec2ConfigurableClient::HidlImpl::querySupportedValues(
532 std::vector<C2FieldSupportedValuesQuery>& fields,
533 c2_blocking_t mayBlock) const {
534 hidl_vec<c2_hidl::FieldSupportedValuesQuery> inFields(fields.size());
535 for (size_t i = 0; i < fields.size(); ++i) {
536 if (!c2_hidl::utils::objcpy(&inFields[i], fields[i])) {
537 LOG(ERROR) << "querySupportedValues -- bad input";
538 return C2_TRANSACTION_FAILED;
539 }
540 }
541
542 c2_status_t status;
543 Return<void> transStatus = mBase->querySupportedValues(
544 inFields,
545 mayBlock == C2_MAY_BLOCK,
546 [&status, &inFields, &fields](
547 c2_hidl::Status s,
548 const hidl_vec<c2_hidl::FieldSupportedValuesQueryResult>& r) {
549 status = static_cast<c2_status_t>(s);
550 if (status != C2_OK) {
551 LOG(DEBUG) << "querySupportedValues -- call failed: "
552 << status << ".";
553 return;
554 }
555 if (r.size() != fields.size()) {
556 LOG(ERROR) << "querySupportedValues -- "
557 "input and output lists "
558 "have different sizes.";
559 status = C2_CORRUPTED;
560 return;
561 }
562 for (size_t i = 0; i < fields.size(); ++i) {
563 if (!c2_hidl::utils::objcpy(&fields[i], inFields[i], r[i])) {
564 LOG(ERROR) << "querySupportedValues -- "
565 "invalid returned value.";
566 status = C2_CORRUPTED;
567 return;
568 }
569 }
570 });
571 if (!transStatus.isOk()) {
572 LOG(ERROR) << "querySupportedValues -- transaction failed.";
573 return C2_TRANSACTION_FAILED;
574 }
575 return status;
576 }
577
578 // Codec2ConfigurableClient::AidlImpl
579
580 struct Codec2ConfigurableClient::AidlImpl : public Codec2ConfigurableClient::ImplBase {
581 typedef c2_aidl::IConfigurable Base;
582
583 // base cannot be null.
584 explicit AidlImpl(const std::shared_ptr<Base>& base);
585
getNameandroid::Codec2ConfigurableClient::AidlImpl586 const C2String& getName() const override {
587 return mName;
588 }
589
590 c2_status_t query(
591 const std::vector<C2Param*>& stackParams,
592 const std::vector<C2Param::Index> &heapParamIndices,
593 c2_blocking_t mayBlock,
594 std::vector<std::unique_ptr<C2Param>>* const heapParams) const override;
595
596 c2_status_t config(
597 const std::vector<C2Param*> ¶ms,
598 c2_blocking_t mayBlock,
599 std::vector<std::unique_ptr<C2SettingResult>>* const failures) override;
600
601 c2_status_t querySupportedParams(
602 std::vector<std::shared_ptr<C2ParamDescriptor>>* const params
603 ) const override;
604
605 c2_status_t querySupportedValues(
606 std::vector<C2FieldSupportedValuesQuery>& fields,
607 c2_blocking_t mayBlock) const override;
608
609 private:
610 std::shared_ptr<Base> mBase;
611 const C2String mName;
612 };
613
AidlImpl(const std::shared_ptr<Base> & base)614 Codec2ConfigurableClient::AidlImpl::AidlImpl(const std::shared_ptr<Base>& base)
615 : mBase{base},
__anon926bcd9b0a02() 616 mName{[base]() -> C2String {
617 std::string outName;
618 ndk::ScopedAStatus status = base->getName(&outName);
619 return status.isOk() ? outName : "";
620 }()} {
621 }
622
query(const std::vector<C2Param * > & stackParams,const std::vector<C2Param::Index> & heapParamIndices,c2_blocking_t mayBlock,std::vector<std::unique_ptr<C2Param>> * const heapParams) const623 c2_status_t Codec2ConfigurableClient::AidlImpl::query(
624 const std::vector<C2Param*> &stackParams,
625 const std::vector<C2Param::Index> &heapParamIndices,
626 c2_blocking_t mayBlock,
627 std::vector<std::unique_ptr<C2Param>>* const heapParams) const {
628 std::vector<int> indices(
629 stackParams.size() + heapParamIndices.size());
630 size_t numIndices = 0;
631 for (C2Param* const& stackParam : stackParams) {
632 if (!stackParam) {
633 LOG(WARNING) << "query -- null stack param encountered.";
634 continue;
635 }
636 indices[numIndices++] = int(stackParam->index());
637 }
638 size_t numStackIndices = numIndices;
639 for (const C2Param::Index& index : heapParamIndices) {
640 indices[numIndices++] = int(static_cast<uint32_t>(index));
641 }
642 indices.resize(numIndices);
643 if (heapParams) {
644 heapParams->reserve(heapParams->size() + numIndices);
645 }
646 c2_aidl::IConfigurable::QueryResult result;
647 ndk::ScopedAStatus transStatus = mBase->query(indices, (mayBlock == C2_MAY_BLOCK), &result);
648 c2_status_t status = GetC2Status(transStatus, "query");
649 if (status != C2_OK) {
650 return status;
651 }
652 status = static_cast<c2_status_t>(result.status.status);
653
654 std::vector<C2Param*> paramPointers;
655 if (!c2_aidl::utils::ParseParamsBlob(¶mPointers, result.params)) {
656 LOG(ERROR) << "query -- error while parsing params.";
657 return C2_CORRUPTED;
658 }
659 size_t i = 0;
660 size_t numQueried = 0;
661 for (auto it = paramPointers.begin(); it != paramPointers.end(); ) {
662 C2Param* paramPointer = *it;
663 if (numStackIndices > 0) {
664 --numStackIndices;
665 if (!paramPointer) {
666 LOG(DEBUG) << "query -- null stack param.";
667 ++it;
668 continue;
669 }
670 for (; i < stackParams.size() && !stackParams[i]; ) {
671 ++i;
672 }
673 if (i >= stackParams.size()) {
674 LOG(ERROR) << "query -- unexpected error.";
675 status = C2_CORRUPTED;
676 break;
677 }
678 if (stackParams[i]->index() != paramPointer->index()) {
679 LOG(DEBUG) << "query -- param skipped: "
680 "index = "
681 << stackParams[i]->index() << ".";
682 stackParams[i++]->invalidate();
683 // this means that the param could not be queried.
684 // signalling C2_BAD_INDEX to the client.
685 status = C2_BAD_INDEX;
686 continue;
687 }
688 if (stackParams[i++]->updateFrom(*paramPointer)) {
689 ++numQueried;
690 } else {
691 LOG(WARNING) << "query -- param update failed: "
692 "index = "
693 << paramPointer->index() << ".";
694 }
695 } else {
696 if (!paramPointer) {
697 LOG(DEBUG) << "query -- null heap param.";
698 ++it;
699 continue;
700 }
701 if (!heapParams) {
702 LOG(WARNING) << "query -- "
703 "unexpected extra stack param.";
704 } else {
705 heapParams->emplace_back(C2Param::Copy(*paramPointer));
706 ++numQueried;
707 }
708 }
709 ++it;
710 }
711 if (status == C2_OK && indices.size() != numQueried) {
712 status = C2_BAD_INDEX;
713 }
714 return status;
715 }
716
config(const std::vector<C2Param * > & params,c2_blocking_t mayBlock,std::vector<std::unique_ptr<C2SettingResult>> * const failures)717 c2_status_t Codec2ConfigurableClient::AidlImpl::config(
718 const std::vector<C2Param*> ¶ms,
719 c2_blocking_t mayBlock,
720 std::vector<std::unique_ptr<C2SettingResult>>* const failures) {
721 c2_aidl::Params aidlParams;
722 if (!c2_aidl::utils::CreateParamsBlob(&aidlParams, params)) {
723 LOG(ERROR) << "config -- bad input.";
724 return C2_TRANSACTION_FAILED;
725 }
726 c2_aidl::IConfigurable::ConfigResult result;
727 ndk::ScopedAStatus transStatus = mBase->config(aidlParams, (mayBlock == C2_MAY_BLOCK), &result);
728 c2_status_t status = GetC2Status(transStatus, "config");
729 if (status != C2_OK) {
730 return status;
731 }
732 status = static_cast<c2_status_t>(result.status.status);
733 size_t i = failures->size();
734 failures->resize(i + result.failures.size());
735 for (const c2_aidl::SettingResult& sf : result.failures) {
736 if (!c2_aidl::utils::FromAidl(&(*failures)[i++], sf)) {
737 LOG(ERROR) << "config -- invalid SettingResult returned.";
738 return C2_CORRUPTED;
739 }
740 }
741 if (!c2_aidl::utils::UpdateParamsFromBlob(params, result.params)) {
742 LOG(ERROR) << "config -- "
743 << "failed to parse returned params.";
744 status = C2_CORRUPTED;
745 }
746 return status;
747 }
748
querySupportedParams(std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const749 c2_status_t Codec2ConfigurableClient::AidlImpl::querySupportedParams(
750 std::vector<std::shared_ptr<C2ParamDescriptor>>* const params) const {
751 // TODO: Cache and query properly!
752 std::vector<c2_aidl::ParamDescriptor> result;
753 ndk::ScopedAStatus transStatus = mBase->querySupportedParams(
754 std::numeric_limits<uint32_t>::min(),
755 std::numeric_limits<uint32_t>::max(),
756 &result);
757 c2_status_t status = GetC2Status(transStatus, "querySupportedParams");
758 if (status != C2_OK) {
759 return status;
760 }
761 size_t i = params->size();
762 params->resize(i + result.size());
763 for (const c2_aidl::ParamDescriptor& sp : result) {
764 if (!c2_aidl::utils::FromAidl(&(*params)[i++], sp)) {
765 LOG(ERROR) << "querySupportedParams -- invalid returned ParamDescriptor.";
766 return C2_CORRUPTED;
767 }
768 }
769 return status;
770 }
771
querySupportedValues(std::vector<C2FieldSupportedValuesQuery> & fields,c2_blocking_t mayBlock) const772 c2_status_t Codec2ConfigurableClient::AidlImpl::querySupportedValues(
773 std::vector<C2FieldSupportedValuesQuery>& fields,
774 c2_blocking_t mayBlock) const {
775 std::vector<c2_aidl::FieldSupportedValuesQuery> inFields(fields.size());
776 for (size_t i = 0; i < fields.size(); ++i) {
777 if (!c2_aidl::utils::ToAidl(&inFields[i], fields[i])) {
778 LOG(ERROR) << "querySupportedValues -- bad input";
779 return C2_TRANSACTION_FAILED;
780 }
781 }
782
783 c2_aidl::IConfigurable::QuerySupportedValuesResult result;
784
785 ndk::ScopedAStatus transStatus = mBase->querySupportedValues(
786 inFields, (mayBlock == C2_MAY_BLOCK), &result);
787 c2_status_t status = GetC2Status(transStatus, "querySupportedValues");
788 if (status != C2_OK) {
789 return status;
790 }
791 status = static_cast<c2_status_t>(result.status.status);
792 if (result.values.size() != fields.size()) {
793 LOG(ERROR) << "querySupportedValues -- "
794 "input and output lists "
795 "have different sizes.";
796 return C2_CORRUPTED;
797 }
798 for (size_t i = 0; i < fields.size(); ++i) {
799 if (!c2_aidl::utils::FromAidl(&fields[i], inFields[i], result.values[i])) {
800 LOG(ERROR) << "querySupportedValues -- "
801 "invalid returned value.";
802 return C2_CORRUPTED;
803 }
804 }
805 return status;
806 }
807
808 // Codec2ConfigurableClient::ApexImpl
809
810 struct Codec2ConfigurableClient::ApexImpl : public Codec2ConfigurableClient::ImplBase {
811 ApexImpl(ApexCodec_Configurable *base, const C2String &name);
812
getNameandroid::Codec2ConfigurableClient::ApexImpl813 const C2String& getName() const override {
814 return mName;
815 }
816
817 c2_status_t query(
818 const std::vector<C2Param*>& stackParams,
819 const std::vector<C2Param::Index> &heapParamIndices,
820 c2_blocking_t mayBlock,
821 std::vector<std::unique_ptr<C2Param>>* const heapParams) const override;
822
823 c2_status_t config(
824 const std::vector<C2Param*> ¶ms,
825 c2_blocking_t mayBlock,
826 std::vector<std::unique_ptr<C2SettingResult>>* const failures) override;
827
828 c2_status_t querySupportedParams(
829 std::vector<std::shared_ptr<C2ParamDescriptor>>* const params
830 ) const override;
831
832 c2_status_t querySupportedValues(
833 std::vector<C2FieldSupportedValuesQuery>& fields,
834 c2_blocking_t mayBlock) const override;
835
836 private:
837 ApexCodec_Configurable* mBase;
838 const C2String mName;
839 };
840
ApexImpl(ApexCodec_Configurable * base,const C2String & name)841 Codec2ConfigurableClient::ApexImpl::ApexImpl(ApexCodec_Configurable *base, const C2String &name)
842 : mBase{base},
843 mName{name} {
844 }
845
query(const std::vector<C2Param * > & stackParams,const std::vector<C2Param::Index> & heapParamIndices,c2_blocking_t mayBlock,std::vector<std::unique_ptr<C2Param>> * const heapParams) const846 c2_status_t Codec2ConfigurableClient::ApexImpl::query(
847 const std::vector<C2Param*> &stackParams,
848 const std::vector<C2Param::Index> &heapParamIndices,
849 [[maybe_unused]] c2_blocking_t mayBlock,
850 std::vector<std::unique_ptr<C2Param>>* const heapParams) const {
851 if (mBase == nullptr) {
852 return C2_OMITTED;
853 }
854
855 if (__builtin_available(android 36, *)) {
856 std::vector<uint32_t> indices(
857 stackParams.size() + heapParamIndices.size());
858 size_t numIndices = 0;
859 for (C2Param* const& stackParam : stackParams) {
860 if (!stackParam) {
861 LOG(WARNING) << "query -- null stack param encountered.";
862 continue;
863 }
864 indices[numIndices++] = uint32_t(stackParam->index());
865 }
866 size_t numStackIndices = numIndices;
867 for (const C2Param::Index& index : heapParamIndices) {
868 indices[numIndices++] = uint32_t(index);
869 }
870 indices.resize(numIndices);
871 if (heapParams) {
872 heapParams->reserve(heapParams->size() + numIndices);
873 }
874 if (numIndices == 0) {
875 return C2_OK;
876 }
877 thread_local std::vector<uint8_t> configBuffer(1024);
878 if (configBuffer.capacity() < numIndices * 16u) {
879 configBuffer.resize(numIndices * 16u);
880 }
881 ApexCodec_LinearBuffer config{configBuffer.data(), configBuffer.capacity()};
882 size_t writtenOrRequested = 0;
883 ApexCodec_Status status = ApexCodec_Configurable_query(
884 mBase, indices.data(), indices.size(), &config, &writtenOrRequested);
885 if (status == APEXCODEC_STATUS_NO_MEMORY) {
886 size_t requested = writtenOrRequested;
887 configBuffer.resize(align(requested, 1024));
888 config.data = configBuffer.data();
889 config.size = configBuffer.capacity();
890 status = ApexCodec_Configurable_query(
891 mBase, indices.data(), indices.size(), &config, &writtenOrRequested);
892 }
893 size_t written = writtenOrRequested;
894 if (status != APEXCODEC_STATUS_OK && status != APEXCODEC_STATUS_BAD_INDEX) {
895 written = 0;
896 }
897 configBuffer.resize(written);
898 std::vector<C2Param*> paramPointers;
899 if (!::android::parseParamsBlob(¶mPointers, configBuffer)) {
900 LOG(ERROR) << "query -- error while parsing params.";
901 return C2_CORRUPTED;
902 }
903 size_t i = 0;
904 size_t numQueried = 0;
905 for (auto it = paramPointers.begin(); it != paramPointers.end(); ) {
906 C2Param* paramPointer = *it;
907 if (numStackIndices > 0) {
908 --numStackIndices;
909 if (!paramPointer) {
910 LOG(DEBUG) << "query -- null stack param.";
911 ++it;
912 continue;
913 }
914 for (; i < stackParams.size() && !stackParams[i]; ) {
915 ++i;
916 }
917 if (i >= stackParams.size()) {
918 LOG(ERROR) << "query -- unexpected error.";
919 status = APEXCODEC_STATUS_CORRUPTED;
920 break;
921 }
922 if (stackParams[i]->index() != paramPointer->index()) {
923 LOG(DEBUG) << "query -- param skipped: "
924 "index = "
925 << stackParams[i]->index() << ".";
926 stackParams[i++]->invalidate();
927 // this means that the param could not be queried.
928 // signalling C2_BAD_INDEX to the client.
929 status = APEXCODEC_STATUS_BAD_INDEX;
930 continue;
931 }
932 if (stackParams[i++]->updateFrom(*paramPointer)) {
933 ++numQueried;
934 } else {
935 LOG(WARNING) << "query -- param update failed: "
936 "index = "
937 << paramPointer->index() << ".";
938 }
939 } else {
940 if (!paramPointer) {
941 LOG(DEBUG) << "query -- null heap param.";
942 ++it;
943 continue;
944 }
945 if (!heapParams) {
946 LOG(WARNING) << "query -- "
947 "unexpected extra stack param.";
948 } else {
949 heapParams->emplace_back(C2Param::Copy(*paramPointer));
950 ++numQueried;
951 }
952 }
953 ++it;
954 }
955 if (status == APEXCODEC_STATUS_OK && indices.size() != numQueried) {
956 status = APEXCODEC_STATUS_BAD_INDEX;
957 }
958 return (c2_status_t)status;
959 } else {
960 return C2_OMITTED;
961 }
962 }
963
964 namespace {
965 struct ParamOrField : public C2ParamField {
ParamOrFieldandroid::__anon926bcd9b0b11::ParamOrField966 explicit ParamOrField(const ApexCodec_ParamFieldValues& field)
967 : C2ParamField(field.index, field.offset, field.size) {}
968 };
969
FromApex(ApexCodec_SupportedValues * apexValues,C2FieldSupportedValues * c2Values)970 static bool FromApex(
971 ApexCodec_SupportedValues *apexValues,
972 C2FieldSupportedValues* c2Values) {
973 if (__builtin_available(android 36, *)) {
974 if (apexValues == nullptr) {
975 c2Values->type = C2FieldSupportedValues::EMPTY;
976 return true;
977 }
978 ApexCodec_SupportedValuesType type = APEXCODEC_SUPPORTED_VALUES_EMPTY;
979 ApexCodec_SupportedValuesNumberType numberType = APEXCODEC_SUPPORTED_VALUES_TYPE_NONE;
980 ApexCodec_Value* values = nullptr;
981 uint32_t numValues = 0;
982 ApexCodec_SupportedValues_getTypeAndValues(
983 apexValues, &type, &numberType, &values, &numValues);
984 c2Values->type = (C2FieldSupportedValues::type_t)type;
985 std::function<C2Value::Primitive(const ApexCodec_Value &)> getPrimitive;
986 switch (numberType) {
987 case APEXCODEC_SUPPORTED_VALUES_TYPE_NONE:
988 getPrimitive = [](const ApexCodec_Value &) -> C2Value::Primitive {
989 return C2Value::Primitive();
990 };
991 break;
992 case APEXCODEC_SUPPORTED_VALUES_TYPE_INT32:
993 getPrimitive = [](const ApexCodec_Value &value) -> C2Value::Primitive {
994 return C2Value::Primitive(value.i32);
995 };
996 break;
997 case APEXCODEC_SUPPORTED_VALUES_TYPE_UINT32:
998 getPrimitive = [](const ApexCodec_Value &value) -> C2Value::Primitive {
999 return C2Value::Primitive(value.u32);
1000 };
1001 break;
1002 case APEXCODEC_SUPPORTED_VALUES_TYPE_INT64:
1003 getPrimitive = [](const ApexCodec_Value &value) -> C2Value::Primitive {
1004 return C2Value::Primitive(value.i64);
1005 };
1006 break;
1007 case APEXCODEC_SUPPORTED_VALUES_TYPE_UINT64:
1008 getPrimitive = [](const ApexCodec_Value &value) -> C2Value::Primitive {
1009 return C2Value::Primitive(value.u64);
1010 };
1011 break;
1012 case APEXCODEC_SUPPORTED_VALUES_TYPE_FLOAT:
1013 getPrimitive = [](const ApexCodec_Value &value) -> C2Value::Primitive {
1014 return C2Value::Primitive(value.f);
1015 };
1016 break;
1017 default:
1018 LOG(ERROR) << "Unsupported number type: " << numberType;
1019 return false;
1020 }
1021 switch (type) {
1022 case APEXCODEC_SUPPORTED_VALUES_EMPTY:
1023 break;
1024 case APEXCODEC_SUPPORTED_VALUES_RANGE:
1025 c2Values->range.min = getPrimitive(values[0]);
1026 c2Values->range.max = getPrimitive(values[1]);
1027 c2Values->range.step = getPrimitive(values[2]);
1028 c2Values->range.num = getPrimitive(values[3]);
1029 c2Values->range.denom = getPrimitive(values[4]);
1030 break;
1031 case APEXCODEC_SUPPORTED_VALUES_VALUES:
1032 case APEXCODEC_SUPPORTED_VALUES_FLAGS:
1033 c2Values->values.clear();
1034 for (uint32_t i = 0; i < numValues; ++i) {
1035 c2Values->values.push_back(getPrimitive(values[i]));
1036 }
1037 break;
1038 default:
1039 LOG(ERROR) << "Unsupported supported values type: " << type;
1040 return false;
1041 }
1042 return true;
1043 } else {
1044 return false;
1045 }
1046 }
1047
1048 } // anonymous namespace
1049
config(const std::vector<C2Param * > & params,c2_blocking_t mayBlock,std::vector<std::unique_ptr<C2SettingResult>> * const failures)1050 c2_status_t Codec2ConfigurableClient::ApexImpl::config(
1051 const std::vector<C2Param*> ¶ms,
1052 c2_blocking_t mayBlock,
1053 std::vector<std::unique_ptr<C2SettingResult>>* const failures) {
1054 (void)mayBlock;
1055 if (mBase == nullptr) {
1056 return C2_OMITTED;
1057 }
1058
1059 if (__builtin_available(android 36, *)) {
1060 std::vector<uint8_t> configBuffer;
1061 if (!::android::_createParamsBlob(&configBuffer, params)) {
1062 LOG(ERROR) << "config -- bad input.";
1063 return C2_TRANSACTION_FAILED;
1064 }
1065 ApexCodec_SettingResults* result = nullptr;
1066 ApexCodec_LinearBuffer config{configBuffer.data(), configBuffer.size()};
1067 ApexCodec_Status status = ApexCodec_Configurable_config(
1068 mBase, &config, &result);
1069 base::ScopeGuard guard([result] {
1070 if (result) {
1071 ApexCodec_SettingResults_destroy(result);
1072 }
1073 });
1074 size_t index = 0;
1075 ApexCodec_SettingResultFailure failure;
1076 ApexCodec_ParamFieldValues field;
1077 ApexCodec_ParamFieldValues* conflicts = nullptr;
1078 size_t numConflicts = 0;
1079 ApexCodec_Status getResultStatus = ApexCodec_SettingResults_getResultAtIndex(
1080 result, 0, &failure, &field, &conflicts, &numConflicts);
1081 while (getResultStatus == APEXCODEC_STATUS_OK) {
1082 std::unique_ptr<C2SettingResult> settingResult;
1083 settingResult.reset(new C2SettingResult{
1084 C2SettingResult::Failure(failure), C2ParamFieldValues(ParamOrField(field)), {}
1085 });
1086 // TODO: settingResult->field.values = ?
1087 for (size_t i = 0; i < numConflicts; ++i) {
1088 settingResult->conflicts.emplace_back(ParamOrField(conflicts[i]));
1089 C2ParamFieldValues& conflict = settingResult->conflicts.back();
1090 conflict.values = std::make_unique<C2FieldSupportedValues>();
1091 FromApex(conflicts[i].values, conflict.values.get());
1092 }
1093 failures->push_back(std::move(settingResult));
1094 getResultStatus = ApexCodec_SettingResults_getResultAtIndex(
1095 result, ++index, &failure, &field, &conflicts, &numConflicts);
1096 }
1097 if (!::android::updateParamsFromBlob(params, configBuffer)) {
1098 LOG(ERROR) << "config -- "
1099 << "failed to parse returned params.";
1100 status = APEXCODEC_STATUS_CORRUPTED;
1101 }
1102 return (c2_status_t)status;
1103 } else {
1104 return C2_OMITTED;
1105 }
1106 }
1107
querySupportedParams(std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const1108 c2_status_t Codec2ConfigurableClient::ApexImpl::querySupportedParams(
1109 std::vector<std::shared_ptr<C2ParamDescriptor>>* const params) const {
1110 if (mBase == nullptr) {
1111 return C2_OMITTED;
1112 }
1113
1114 if (__builtin_available(android 36, *)) {
1115 // TODO: Cache and query properly!
1116 ApexCodec_ParamDescriptors* paramDescs = nullptr;
1117 ApexCodec_Configurable_querySupportedParams(mBase, ¶mDescs);
1118 base::ScopeGuard guard([paramDescs] {
1119 if (paramDescs) {
1120 ApexCodec_ParamDescriptors_destroy(paramDescs);
1121 }
1122 });
1123 uint32_t *indices = nullptr;
1124 size_t numIndices = 0;
1125 ApexCodec_Status status = ApexCodec_ParamDescriptors_getIndices(
1126 paramDescs, &indices, &numIndices);
1127 if (status != APEXCODEC_STATUS_OK) {
1128 return (c2_status_t)status;
1129 }
1130 if (numIndices > 0) {
1131 for (int i = 0; i < numIndices; ++i) {
1132 uint32_t index = indices[i];
1133 ApexCodec_ParamAttribute attr = (ApexCodec_ParamAttribute)0;
1134 const char* name = nullptr;
1135 uint32_t* dependencies = nullptr;
1136 size_t numDependencies = 0;
1137 ApexCodec_Status status = ApexCodec_ParamDescriptors_getDescriptor(
1138 paramDescs, index, &attr, &name, &dependencies, &numDependencies);
1139 if (status != APEXCODEC_STATUS_OK) {
1140 LOG(WARNING) << "querySupportedParams -- "
1141 << "failed to get descriptor for index "
1142 << std::hex << index << std::dec << " with status " << status;
1143 continue;
1144 }
1145 params->push_back(std::make_shared<C2ParamDescriptor>(
1146 C2Param::Index(index), C2ParamDescriptor::attrib_t(attr), name,
1147 std::vector<C2Param::Index>(dependencies, dependencies + numDependencies)));
1148 }
1149 }
1150 return (c2_status_t)status;
1151 } else {
1152 return C2_OMITTED;
1153 }
1154 }
1155
querySupportedValues(std::vector<C2FieldSupportedValuesQuery> & fields,c2_blocking_t mayBlock) const1156 c2_status_t Codec2ConfigurableClient::ApexImpl::querySupportedValues(
1157 std::vector<C2FieldSupportedValuesQuery>& fields,
1158 [[maybe_unused]] c2_blocking_t mayBlock) const {
1159 if (mBase == nullptr) {
1160 return C2_OMITTED;
1161 }
1162
1163 if (__builtin_available(android 36, *)) {
1164 std::vector<ApexCodec_SupportedValuesQuery> queries(fields.size());
1165 for (size_t i = 0; i < fields.size(); ++i) {
1166 queries[i].index = _C2ParamInspector::GetIndex(fields[i].field());
1167 queries[i].offset = _C2ParamInspector::GetOffset(fields[i].field());
1168 queries[i].type = (ApexCodec_SupportedValuesQueryType)fields[i].type();
1169 queries[i].status = APEXCODEC_STATUS_OK;
1170 queries[i].values = nullptr;
1171 }
1172 ApexCodec_Status status = ApexCodec_Configurable_querySupportedValues(
1173 mBase, queries.data(), queries.size());
1174 for (size_t i = 0; i < fields.size(); ++i) {
1175 fields[i].status = (c2_status_t)queries[i].status;
1176 FromApex(queries[i].values, &fields[i].values);
1177 if (queries[i].values) {
1178 ApexCodec_SupportedValues_destroy(queries[i].values);
1179 queries[i].values = nullptr;
1180 }
1181 }
1182 return (c2_status_t)status;
1183 } else {
1184 return C2_OMITTED;
1185 }
1186 }
1187
1188 // Codec2ConfigurableClient
1189
Codec2ConfigurableClient(const sp<HidlBase> & hidlBase)1190 Codec2ConfigurableClient::Codec2ConfigurableClient(const sp<HidlBase> &hidlBase)
1191 : mImpl(new Codec2ConfigurableClient::HidlImpl(hidlBase)) {
1192 }
1193
Codec2ConfigurableClient(const std::shared_ptr<AidlBase> & aidlBase)1194 Codec2ConfigurableClient::Codec2ConfigurableClient(
1195 const std::shared_ptr<AidlBase> &aidlBase)
1196 : mImpl(new Codec2ConfigurableClient::AidlImpl(aidlBase)) {
1197 }
1198
Codec2ConfigurableClient(ApexCodec_Configurable * apexBase,const C2String & name)1199 Codec2ConfigurableClient::Codec2ConfigurableClient(
1200 ApexCodec_Configurable *apexBase, const C2String &name)
1201 : mImpl(new Codec2ConfigurableClient::ApexImpl(apexBase, name)) {
1202 }
1203
getName() const1204 const C2String& Codec2ConfigurableClient::getName() const {
1205 return mImpl->getName();
1206 }
1207
query(const std::vector<C2Param * > & stackParams,const std::vector<C2Param::Index> & heapParamIndices,c2_blocking_t mayBlock,std::vector<std::unique_ptr<C2Param>> * const heapParams) const1208 c2_status_t Codec2ConfigurableClient::query(
1209 const std::vector<C2Param*>& stackParams,
1210 const std::vector<C2Param::Index> &heapParamIndices,
1211 c2_blocking_t mayBlock,
1212 std::vector<std::unique_ptr<C2Param>>* const heapParams) const {
1213 return mImpl->query(stackParams, heapParamIndices, mayBlock, heapParams);
1214 }
1215
config(const std::vector<C2Param * > & params,c2_blocking_t mayBlock,std::vector<std::unique_ptr<C2SettingResult>> * const failures)1216 c2_status_t Codec2ConfigurableClient::config(
1217 const std::vector<C2Param*> ¶ms,
1218 c2_blocking_t mayBlock,
1219 std::vector<std::unique_ptr<C2SettingResult>>* const failures) {
1220 return mImpl->config(params, mayBlock, failures);
1221 }
1222
querySupportedParams(std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const1223 c2_status_t Codec2ConfigurableClient::querySupportedParams(
1224 std::vector<std::shared_ptr<C2ParamDescriptor>>* const params) const {
1225 return mImpl->querySupportedParams(params);
1226 }
1227
querySupportedValues(std::vector<C2FieldSupportedValuesQuery> & fields,c2_blocking_t mayBlock) const1228 c2_status_t Codec2ConfigurableClient::querySupportedValues(
1229 std::vector<C2FieldSupportedValuesQuery>& fields,
1230 c2_blocking_t mayBlock) const {
1231 return mImpl->querySupportedValues(fields, mayBlock);
1232 }
1233
1234
1235 // Codec2Client::Component::HidlListener
1236 struct Codec2Client::Component::HidlListener : public c2_hidl::IComponentListener {
1237 std::weak_ptr<Component> component;
1238 std::weak_ptr<Listener> base;
1239
onWorkDoneandroid::Codec2Client::Component::HidlListener1240 virtual Return<void> onWorkDone(const c2_hidl::WorkBundle& workBundle) override {
1241 std::list<std::unique_ptr<C2Work>> workItems;
1242 if (!c2_hidl::utils::objcpy(&workItems, workBundle)) {
1243 LOG(DEBUG) << "onWorkDone -- received corrupted WorkBundle.";
1244 return Void();
1245 }
1246 // release input buffers potentially held by the component from queue
1247 std::shared_ptr<Codec2Client::Component> strongComponent =
1248 component.lock();
1249 if (strongComponent) {
1250 strongComponent->handleOnWorkDone(workItems);
1251 }
1252 if (std::shared_ptr<Codec2Client::Listener> listener = base.lock()) {
1253 listener->onWorkDone(component, workItems);
1254 } else {
1255 LOG(DEBUG) << "onWorkDone -- listener died.";
1256 }
1257 return Void();
1258 }
1259
onTrippedandroid::Codec2Client::Component::HidlListener1260 virtual Return<void> onTripped(
1261 const hidl_vec<c2_hidl::SettingResult>& settingResults) override {
1262 std::vector<std::shared_ptr<C2SettingResult>> c2SettingResults(
1263 settingResults.size());
1264 for (size_t i = 0; i < settingResults.size(); ++i) {
1265 std::unique_ptr<C2SettingResult> c2SettingResult;
1266 if (!c2_hidl::utils::objcpy(&c2SettingResult, settingResults[i])) {
1267 LOG(DEBUG) << "onTripped -- received corrupted SettingResult.";
1268 return Void();
1269 }
1270 c2SettingResults[i] = std::move(c2SettingResult);
1271 }
1272 if (std::shared_ptr<Codec2Client::Listener> listener = base.lock()) {
1273 listener->onTripped(component, c2SettingResults);
1274 } else {
1275 LOG(DEBUG) << "onTripped -- listener died.";
1276 }
1277 return Void();
1278 }
1279
onErrorandroid::Codec2Client::Component::HidlListener1280 virtual Return<void> onError(c2_hidl::Status s, uint32_t errorCode) override {
1281 LOG(DEBUG) << "onError --"
1282 << " status = " << s
1283 << ", errorCode = " << errorCode
1284 << ".";
1285 if (std::shared_ptr<Listener> listener = base.lock()) {
1286 listener->onError(component, s == c2_hidl::Status::OK ?
1287 errorCode : static_cast<c2_status_t>(s));
1288 } else {
1289 LOG(DEBUG) << "onError -- listener died.";
1290 }
1291 return Void();
1292 }
1293
onFramesRenderedandroid::Codec2Client::Component::HidlListener1294 virtual Return<void> onFramesRendered(
1295 const hidl_vec<RenderedFrame>& renderedFrames) override {
1296 std::shared_ptr<Listener> listener = base.lock();
1297 if (!listener) {
1298 LOG(DEBUG) << "onFramesRendered -- listener died.";
1299 return Void();
1300 }
1301 for (const RenderedFrame& renderedFrame : renderedFrames) {
1302 listener->onFrameRendered(
1303 renderedFrame.bufferQueueId,
1304 renderedFrame.slotId,
1305 renderedFrame.timestampNs);
1306 }
1307 return Void();
1308 }
1309
onInputBuffersReleasedandroid::Codec2Client::Component::HidlListener1310 virtual Return<void> onInputBuffersReleased(
1311 const hidl_vec<InputBuffer>& inputBuffers) override {
1312 std::shared_ptr<Listener> listener = base.lock();
1313 if (!listener) {
1314 LOG(DEBUG) << "onInputBuffersReleased -- listener died.";
1315 return Void();
1316 }
1317 for (const InputBuffer& inputBuffer : inputBuffers) {
1318 LOG(VERBOSE) << "onInputBuffersReleased --"
1319 " received death notification of"
1320 " input buffer:"
1321 " frameIndex = " << inputBuffer.frameIndex
1322 << ", bufferIndex = " << inputBuffer.arrayIndex
1323 << ".";
1324 listener->onInputBufferDone(
1325 inputBuffer.frameIndex, inputBuffer.arrayIndex);
1326 }
1327 return Void();
1328 }
1329
1330 };
1331
1332 // Codec2Client::Component::AidlListener
1333 struct Codec2Client::Component::AidlListener : public c2_aidl::BnComponentListener {
1334 std::weak_ptr<Component> component;
1335 std::weak_ptr<Listener> base;
1336
onWorkDoneandroid::Codec2Client::Component::AidlListener1337 virtual ::ndk::ScopedAStatus onWorkDone(const c2_aidl::WorkBundle& workBundle) override {
1338 std::list<std::unique_ptr<C2Work>> workItems;
1339 if (!c2_aidl::utils::FromAidl(&workItems, workBundle)) {
1340 LOG(DEBUG) << "onWorkDone -- received corrupted WorkBundle.";
1341 return ::ndk::ScopedAStatus::ok();
1342 }
1343 // release input buffers potentially held by the component from queue
1344 std::shared_ptr<Codec2Client::Component> strongComponent =
1345 component.lock();
1346 if (strongComponent) {
1347 strongComponent->handleOnWorkDone(workItems);
1348 }
1349 if (std::shared_ptr<Codec2Client::Listener> listener = base.lock()) {
1350 listener->onWorkDone(component, workItems);
1351 } else {
1352 LOG(DEBUG) << "onWorkDone -- listener died.";
1353 }
1354 return ::ndk::ScopedAStatus::ok();
1355 }
1356
onTrippedandroid::Codec2Client::Component::AidlListener1357 virtual ::ndk::ScopedAStatus onTripped(
1358 const std::vector<c2_aidl::SettingResult>& settingResults) override {
1359 std::vector<std::shared_ptr<C2SettingResult>> c2SettingResults(
1360 settingResults.size());
1361 for (size_t i = 0; i < settingResults.size(); ++i) {
1362 std::unique_ptr<C2SettingResult> c2SettingResult;
1363 if (!c2_aidl::utils::FromAidl(&c2SettingResult, settingResults[i])) {
1364 LOG(DEBUG) << "onTripped -- received corrupted SettingResult.";
1365 return ::ndk::ScopedAStatus::ok();
1366 }
1367 c2SettingResults[i] = std::move(c2SettingResult);
1368 }
1369 if (std::shared_ptr<Codec2Client::Listener> listener = base.lock()) {
1370 listener->onTripped(component, c2SettingResults);
1371 } else {
1372 LOG(DEBUG) << "onTripped -- listener died.";
1373 }
1374 return ::ndk::ScopedAStatus::ok();
1375 }
1376
onErrorandroid::Codec2Client::Component::AidlListener1377 virtual ::ndk::ScopedAStatus onError(const c2_aidl::Status &s, int32_t errorCode) override {
1378 LOG(DEBUG) << "onError --"
1379 << " status = " << s.status
1380 << ", errorCode = " << errorCode
1381 << ".";
1382 if (std::shared_ptr<Listener> listener = base.lock()) {
1383 listener->onError(component, s.status == c2_aidl::Status::OK ?
1384 errorCode : static_cast<c2_status_t>(s.status));
1385 } else {
1386 LOG(DEBUG) << "onError -- listener died.";
1387 }
1388 return ::ndk::ScopedAStatus::ok();
1389 }
1390
onFramesRenderedandroid::Codec2Client::Component::AidlListener1391 virtual ::ndk::ScopedAStatus onFramesRendered(
1392 const std::vector<RenderedFrame>& renderedFrames) override {
1393 std::shared_ptr<Listener> listener = base.lock();
1394 if (!listener) {
1395 LOG(DEBUG) << "onFramesRendered -- listener died.";
1396 return ::ndk::ScopedAStatus::ok();
1397 }
1398 for (const RenderedFrame& renderedFrame : renderedFrames) {
1399 listener->onFrameRendered(
1400 renderedFrame.bufferQueueId,
1401 renderedFrame.slotId,
1402 renderedFrame.timestampNs);
1403 }
1404 return ::ndk::ScopedAStatus::ok();
1405 }
1406
onInputBuffersReleasedandroid::Codec2Client::Component::AidlListener1407 virtual ::ndk::ScopedAStatus onInputBuffersReleased(
1408 const std::vector<InputBuffer>& inputBuffers) override {
1409 std::shared_ptr<Listener> listener = base.lock();
1410 if (!listener) {
1411 LOG(DEBUG) << "onInputBuffersReleased -- listener died.";
1412 return ::ndk::ScopedAStatus::ok();
1413 }
1414 for (const InputBuffer& inputBuffer : inputBuffers) {
1415 LOG(VERBOSE) << "onInputBuffersReleased --"
1416 " received death notification of"
1417 " input buffer:"
1418 " frameIndex = " << inputBuffer.frameIndex
1419 << ", bufferIndex = " << inputBuffer.arrayIndex
1420 << ".";
1421 listener->onInputBufferDone(
1422 inputBuffer.frameIndex, inputBuffer.arrayIndex);
1423 }
1424 return ::ndk::ScopedAStatus::ok();
1425 }
1426
1427 };
1428
1429 // Codec2Client::Component::ApexHandler
1430 class Codec2Client::Component::ApexHandler {
1431 public:
ApexHandler(ApexCodec_Component * apexComponent,const std::shared_ptr<Listener> & listener,const std::shared_ptr<Component> & comp)1432 ApexHandler(ApexCodec_Component *apexComponent,
1433 const std::shared_ptr<Listener> &listener,
1434 const std::shared_ptr<Component> &comp)
1435 : mApexComponent(apexComponent),
1436 mListener(listener),
1437 mComponent(comp),
1438 mStopped(false),
1439 mOutputBufferType(APEXCODEC_BUFFER_TYPE_EMPTY) {
1440 }
1441
start()1442 void start() {
1443 std::shared_ptr<Component> comp = mComponent.lock();
1444 if (!comp) {
1445 LOG(ERROR) << "ApexHandler::start -- component died.";
1446 return;
1447 }
1448 C2ComponentDomainSetting domain;
1449 C2ComponentKindSetting kind;
1450 c2_status_t status = comp->query({&domain, &kind}, {}, C2_MAY_BLOCK, {});
1451 if (status != C2_OK) {
1452 LOG(ERROR) << "ApexHandler::start -- failed to query component domain and kind";
1453 return;
1454 }
1455 if (kind.value != C2Component::KIND_DECODER
1456 && kind.value != C2Component::KIND_ENCODER) {
1457 LOG(ERROR) << "ApexHandler::start -- unrecognized component kind " << kind.value;
1458 return;
1459 }
1460 ApexCodec_BufferType outputBufferType = APEXCODEC_BUFFER_TYPE_EMPTY;
1461 if (domain.value == C2Component::DOMAIN_AUDIO) {
1462 // For both encoders and decoders the output buffer type is linear.
1463 outputBufferType = APEXCODEC_BUFFER_TYPE_LINEAR;
1464 } else if (domain.value == C2Component::DOMAIN_VIDEO
1465 || domain.value == C2Component::DOMAIN_IMAGE) {
1466 // For video / image domain the decoder outputs a graphic buffer, and the encoder
1467 // outputs a linear buffer.
1468 outputBufferType = (kind.value == C2Component::KIND_DECODER)
1469 ? APEXCODEC_BUFFER_TYPE_GRAPHIC : APEXCODEC_BUFFER_TYPE_LINEAR;
1470 } else {
1471 LOG(ERROR) << "ApexHandler::start -- unrecognized component domain " << domain.value;
1472 return;
1473 }
1474 {
1475 std::unique_lock<std::mutex> l(mMutex);
1476 mStopped = false;
1477 mOutputBufferType = outputBufferType;
1478 }
1479 mThread = std::thread([this]() {
1480 run();
1481 });
1482 }
1483
queue(std::list<std::unique_ptr<C2Work>> & workItems)1484 void queue(std::list<std::unique_ptr<C2Work>>& workItems) {
1485 std::unique_lock<std::mutex> l(mMutex);
1486 mWorkQueue.splice(mWorkQueue.end(), workItems);
1487 mCondition.notify_all();
1488 }
1489
stop()1490 void stop() {
1491 std::unique_lock<std::mutex> l(mMutex);
1492 mStopped = true;
1493 mCondition.notify_all();
1494 l.unlock();
1495 mThread.join();
1496 }
1497
1498 private:
run()1499 void run() {
1500 while (true) {
1501 std::unique_lock<std::mutex> l(mMutex);
1502 mCondition.wait(l, [this]() {
1503 return !mWorkQueue.empty() || mStopped;
1504 });
1505 if (mStopped) {
1506 break;
1507 }
1508 if (mWorkQueue.empty()) {
1509 continue;
1510 }
1511 std::list<std::unique_ptr<C2Work>> workItems;
1512 mWorkQueue.swap(workItems);
1513 for (std::unique_ptr<C2Work>& workItem : workItems) {
1514 if (mStopped) {
1515 break;
1516 }
1517 l.unlock();
1518 handleWork(std::move(workItem));
1519 l.lock();
1520 }
1521 }
1522 mWorkQueue.clear();
1523 mWorkMap.clear();
1524 }
1525
handleWork(std::unique_ptr<C2Work> && workItem)1526 void handleWork(std::unique_ptr<C2Work> &&workItem) {
1527 if (__builtin_available(android 36, *)) {
1528 std::shared_ptr<Listener> listener = mListener.lock();
1529 if (!listener) {
1530 LOG(DEBUG) << "handleWork -- listener died.";
1531 return;
1532 }
1533 thread_local ApexCodec_Buffer *input = ApexCodec_Buffer_create();
1534 ApexCodec_Buffer_clear(input);
1535 ApexCodec_BufferFlags flags = (ApexCodec_BufferFlags)workItem->input.flags;
1536 uint64_t frameIndex = workItem->input.ordinal.frameIndex.peekll();
1537 uint64_t timestampUs = workItem->input.ordinal.timestamp.peekll();
1538
1539 if (workItem->input.buffers.size() > 1) {
1540 LOG(ERROR) << "handleWork -- input buffer size is "
1541 << workItem->input.buffers.size();
1542 return;
1543 }
1544 std::shared_ptr<C2Buffer> buffer;
1545 std::optional<C2ReadView> linearView;
1546 if (!workItem->input.buffers.empty()) {
1547 buffer = workItem->input.buffers[0];
1548 }
1549 if (!FillMemory(buffer, input, &linearView, flags, frameIndex, timestampUs)) {
1550 LOG(ERROR) << "handleWork -- failed to map input";
1551 return;
1552 }
1553
1554 std::vector<uint8_t> configUpdatesVector;
1555 if (!_createParamsBlob(&configUpdatesVector, workItem->input.configUpdate)) {
1556 listener->onError(mComponent, C2_CORRUPTED);
1557 return;
1558 }
1559 ApexCodec_LinearBuffer configUpdates;
1560 configUpdates.data = configUpdatesVector.data();
1561 configUpdates.size = configUpdatesVector.size();
1562 ApexCodec_Buffer_setConfigUpdates(input, &configUpdates);
1563 mWorkMap.insert_or_assign(
1564 workItem->input.ordinal.frameIndex.peekll(), std::move(workItem));
1565
1566 std::list<std::unique_ptr<C2Work>> workItems;
1567 bool inputDrained = false;
1568 while (!inputDrained) {
1569 thread_local ApexCodec_Buffer *output = ApexCodec_Buffer_create();
1570 ApexCodec_Buffer_clear(output);
1571 std::shared_ptr<C2LinearBlock> linearBlock;
1572 std::optional<C2WriteView> linearView;
1573 std::shared_ptr<C2GraphicBlock> graphicBlock;
1574 allocOutputBuffer(output, &linearBlock, &linearView, &graphicBlock);
1575 size_t consumed = 0;
1576 size_t produced = 0;
1577 ApexCodec_Status status = ApexCodec_Component_process(
1578 mApexComponent, input, output, &consumed, &produced);
1579 if (status == APEXCODEC_STATUS_NO_MEMORY) {
1580 continue;
1581 } else if (status != APEXCODEC_STATUS_OK) {
1582 LOG(ERROR) << "handleWork -- component process failed with status " << status;
1583 produced = 0;
1584 }
1585 if (produced > 0) {
1586 ApexCodec_BufferFlags outputFlags;
1587 uint64_t outputFrameIndex;
1588 uint64_t outputTimestampUs;
1589 ApexCodec_Status status = ApexCodec_Buffer_getBufferInfo(
1590 output, &outputFlags, &outputFrameIndex, &outputTimestampUs);
1591 if (status != APEXCODEC_STATUS_OK) {
1592 LOG(WARNING) << "handleWork -- failed to get output buffer info";
1593 outputFrameIndex = ~(uint64_t(0));
1594 }
1595 auto it = mWorkMap.find(outputFrameIndex);
1596 std::unique_ptr<C2Work> outputWorkItem;
1597 if (it != mWorkMap.end()) {
1598 if (outputFlags & APEXCODEC_FLAG_INCOMPLETE) {
1599 outputWorkItem = std::make_unique<C2Work>();
1600 outputWorkItem->input.ordinal = it->second->input.ordinal;
1601 outputWorkItem->input.flags = it->second->input.flags;
1602 } else {
1603 outputWorkItem = std::move(it->second);
1604 mWorkMap.erase(it);
1605 }
1606 } else {
1607 LOG(WARNING) << "handleWork -- no work item found for output frame index "
1608 << outputFrameIndex;
1609 outputWorkItem = std::make_unique<C2Work>();
1610 outputWorkItem->input.ordinal.frameIndex = outputFrameIndex;
1611 outputWorkItem->input.ordinal.timestamp = outputTimestampUs;
1612 }
1613 outputWorkItem->worklets.emplace_back(new C2Worklet);
1614 const std::unique_ptr<C2Worklet> &worklet = outputWorkItem->worklets.front();
1615 if (worklet == nullptr) {
1616 LOG(ERROR) << "handleWork -- output work item has null worklet";
1617 return;
1618 }
1619 worklet->output.ordinal.frameIndex = outputFrameIndex;
1620 worklet->output.ordinal.timestamp = outputTimestampUs;
1621 ApexCodec_LinearBuffer outputConfigUpdates;
1622 bool ownedByClient = false;
1623 status = ApexCodec_Buffer_getConfigUpdates(
1624 output, &outputConfigUpdates, &ownedByClient);
1625 if (status != APEXCODEC_STATUS_OK) {
1626 LOG(WARNING) << "handleWork -- failed to get output config updates";
1627 return;
1628 } else if (ownedByClient) {
1629 LOG(WARNING) << "handleWork -- output config updates are owned by client";
1630 return;
1631 }
1632 // non-owning hidl_vec<> to wrap around the output config updates
1633 hidl_vec<uint8_t> outputConfigUpdatesVec;
1634 outputConfigUpdatesVec.setToExternal(
1635 outputConfigUpdates.data, outputConfigUpdates.size);
1636 std::vector<C2Param*> outputConfigUpdatePtrs;
1637 parseParamsBlob(&outputConfigUpdatePtrs, outputConfigUpdatesVec);
1638 worklet->output.configUpdate.clear();
1639 std::ranges::transform(
1640 outputConfigUpdatePtrs,
1641 std::back_inserter(worklet->output.configUpdate),
1642 [](C2Param* param) { return C2Param::Copy(*param); });
1643 worklet->output.flags = (C2FrameData::flags_t)outputFlags;
1644
1645 workItems.push_back(std::move(outputWorkItem));
1646 }
1647
1648 ApexCodec_BufferType inputType = ApexCodec_Buffer_getType(input);
1649 // determine whether the input buffer is drained
1650 if (inputType == APEXCODEC_BUFFER_TYPE_LINEAR) {
1651 ApexCodec_LinearBuffer inputBuffer;
1652 status = ApexCodec_Buffer_getLinearBuffer(input, &inputBuffer);
1653 if (status != APEXCODEC_STATUS_OK) {
1654 LOG(WARNING) << "handleWork -- failed to get input linear buffer";
1655 inputDrained = true;
1656 } else if (inputBuffer.size < consumed) {
1657 LOG(WARNING) << "handleWork -- component consumed more bytes "
1658 << "than the input buffer size";
1659 inputDrained = true;
1660 } else {
1661 inputBuffer.data += consumed;
1662 inputBuffer.size -= consumed;
1663 }
1664 } else if (inputType == APEXCODEC_BUFFER_TYPE_GRAPHIC) {
1665 inputDrained = (consumed > 0);
1666 }
1667 }
1668
1669 if (!workItems.empty()) {
1670 listener->onWorkDone(mComponent, workItems);
1671 }
1672 }
1673 }
1674
ensureBlockPool()1675 bool ensureBlockPool() {
1676 std::shared_ptr<Component> comp = mComponent.lock();
1677 if (!comp) {
1678 return false;
1679 }
1680 std::vector<std::unique_ptr<C2Param>> heapParams;
1681 comp->query({}, {C2PortBlockPoolsTuning::output::PARAM_TYPE}, C2_MAY_BLOCK, &heapParams);
1682 if (heapParams.size() != 1) {
1683 return false;
1684 }
1685 const C2Param* param = heapParams[0].get();
1686 if (param->type() != C2PortBlockPoolsTuning::output::PARAM_TYPE) {
1687 return false;
1688 }
1689 const C2PortBlockPoolsTuning::output *blockPools =
1690 static_cast<const C2PortBlockPoolsTuning::output *>(param);
1691 if (blockPools->flexCount() == 0) {
1692 return false;
1693 }
1694 C2BlockPool::local_id_t blockPoolId = blockPools->m.values[0];
1695 if (mBlockPool && mBlockPool->getLocalId() == blockPoolId) {
1696 // no need to update
1697 return true;
1698 }
1699 return C2_OK == GetCodec2BlockPool(blockPoolId, nullptr, &mBlockPool);
1700 }
1701
allocOutputBuffer(ApexCodec_Buffer * output,std::shared_ptr<C2LinearBlock> * linearBlock,std::optional<C2WriteView> * linearView,std::shared_ptr<C2GraphicBlock> * graphicBlock)1702 void allocOutputBuffer(
1703 ApexCodec_Buffer* output,
1704 std::shared_ptr<C2LinearBlock> *linearBlock,
1705 std::optional<C2WriteView> *linearView,
1706 std::shared_ptr<C2GraphicBlock> *graphicBlock) {
1707 if (__builtin_available(android 36, *)) {
1708 switch (mOutputBufferType) {
1709 case APEXCODEC_BUFFER_TYPE_LINEAR: {
1710 if (!ensureBlockPool()) {
1711 return;
1712 }
1713 {
1714 std::shared_ptr<Component> comp = mComponent.lock();
1715 if (!comp) {
1716 return;
1717 }
1718 C2StreamMaxBufferSizeInfo::output maxBufferSize(0u /* stream */);
1719 comp->query({&maxBufferSize}, {}, C2_MAY_BLOCK, {});
1720 mLinearBlockCapacity = maxBufferSize ? maxBufferSize.value : 1024 * 1024;
1721 }
1722 c2_status_t status = mBlockPool->fetchLinearBlock(
1723 mLinearBlockCapacity,
1724 C2MemoryUsage(C2MemoryUsage::CPU_READ | C2MemoryUsage::CPU_WRITE),
1725 linearBlock);
1726 if (!(*linearBlock)) {
1727 return;
1728 }
1729 linearView->emplace((*linearBlock)->map().get());
1730 if ((*linearView)->error() != C2_OK) {
1731 return;
1732 }
1733 ApexCodec_LinearBuffer linear;
1734 linear.data = (*linearView)->data();
1735 linear.size = (*linearView)->capacity();
1736 ApexCodec_Status apexStatus = ApexCodec_Buffer_setLinearBuffer(
1737 output, &linear);
1738 if (apexStatus != APEXCODEC_STATUS_OK) {
1739 LOG(ERROR) << "allocOutputBuffer -- failed to set linear buffer";
1740 return;
1741 }
1742 break;
1743 }
1744 case APEXCODEC_BUFFER_TYPE_GRAPHIC: {
1745 if (!ensureBlockPool()) {
1746 return;
1747 }
1748 {
1749 std::shared_ptr<Component> comp = mComponent.lock();
1750 if (!comp) {
1751 return;
1752 }
1753 C2StreamMaxPictureSizeTuning::output maxPictureSize(0u /* stream */);
1754 C2StreamPictureSizeInfo::output pictureSize(0u /* stream */);
1755 C2StreamPixelFormatInfo::output pixelFormat(0u /* stream */);
1756 comp->query({&maxPictureSize, &pictureSize, &pixelFormat},
1757 {}, C2_MAY_BLOCK, {});
1758 mWidth = maxPictureSize ? maxPictureSize.width : pictureSize.width;
1759 mHeight = maxPictureSize ? maxPictureSize.height : pictureSize.height;
1760 mFormat = pixelFormat ? pixelFormat.value : HAL_PIXEL_FORMAT_YCBCR_420_888;
1761 }
1762 c2_status_t status = mBlockPool->fetchGraphicBlock(
1763 mWidth, mHeight, mFormat,
1764 C2MemoryUsage(C2MemoryUsage::CPU_READ | C2MemoryUsage::CPU_WRITE),
1765 graphicBlock);
1766 if (!(*graphicBlock)) {
1767 return;
1768 }
1769 const C2Handle *handle = (*graphicBlock)->handle();
1770 uint32_t width, height, format, stride, igbp_slot, generation;
1771 uint64_t usage, igbp_id;
1772 _UnwrapNativeCodec2GrallocMetadata(
1773 handle, &width, &height, &format, &usage, &stride, &generation,
1774 &igbp_id, &igbp_slot);
1775 native_handle_t *grallocHandle = UnwrapNativeCodec2GrallocHandle(handle);
1776 sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(
1777 grallocHandle, GraphicBuffer::CLONE_HANDLE,
1778 width, height, format, 1, usage, stride);
1779 native_handle_delete(grallocHandle);
1780 AHardwareBuffer *hardwareBuffer =
1781 AHardwareBuffer_from_GraphicBuffer(graphicBuffer.get());
1782 AHardwareBuffer_acquire(hardwareBuffer);
1783 ApexCodec_Status apexStatus = ApexCodec_Buffer_setGraphicBuffer(
1784 output, hardwareBuffer);
1785 if (apexStatus != APEXCODEC_STATUS_OK) {
1786 LOG(ERROR) << "allocOutputBuffer -- failed to set graphic buffer";
1787 return;
1788 }
1789 break;
1790 }
1791 default: {
1792 LOG(ERROR) << "allocOutputBuffer -- unsupported output buffer type: "
1793 << mOutputBufferType;
1794 return;
1795 }
1796 }
1797 } else {
1798 LOG(ERROR) << "allocOutputBuffer -- ApexCodec is not supported";
1799 }
1800 }
1801
FillMemory(const std::shared_ptr<C2Buffer> & buffer,ApexCodec_Buffer * apexBuffer,std::optional<C2ReadView> * linearView,ApexCodec_BufferFlags flags,uint64_t frameIndex,uint64_t timestampUs)1802 static bool FillMemory(
1803 const std::shared_ptr<C2Buffer>& buffer,
1804 ApexCodec_Buffer* apexBuffer,
1805 std::optional<C2ReadView>* linearView,
1806 ApexCodec_BufferFlags flags,
1807 uint64_t frameIndex,
1808 uint64_t timestampUs) {
1809 if (__builtin_available(android 36, *)) {
1810 if (buffer->data().type() == C2BufferData::LINEAR) {
1811 if (buffer->data().linearBlocks().empty()) {
1812 ApexCodec_Status status = ApexCodec_Buffer_setLinearBuffer(apexBuffer, nullptr);
1813 if (status != APEXCODEC_STATUS_OK) {
1814 LOG(ERROR) << "FillMemory -- failed to set linear buffer";
1815 return false;
1816 }
1817 ApexCodec_Buffer_setBufferInfo(apexBuffer, flags, frameIndex, timestampUs);
1818 return true;
1819 } else if (buffer->data().linearBlocks().size() > 1) {
1820 return false;
1821 }
1822 linearView->emplace(buffer->data().linearBlocks().front().map().get());
1823 if ((*linearView)->error() != C2_OK) {
1824 return false;
1825 }
1826 ApexCodec_LinearBuffer linear;
1827 linear.data = const_cast<uint8_t*>((*linearView)->data());
1828 linear.size = (*linearView)->capacity();
1829 ApexCodec_Status status = ApexCodec_Buffer_setLinearBuffer(apexBuffer, &linear);
1830 if (status != APEXCODEC_STATUS_OK) {
1831 LOG(ERROR) << "FillMemory -- failed to set linear buffer";
1832 return false;
1833 }
1834 ApexCodec_Buffer_setBufferInfo(apexBuffer, flags, frameIndex, timestampUs);
1835 return true;
1836 } else if (buffer->data().type() == C2BufferData::GRAPHIC) {
1837 if (buffer->data().graphicBlocks().empty()) {
1838 ApexCodec_Status status = ApexCodec_Buffer_setGraphicBuffer(
1839 apexBuffer, nullptr);
1840 if (status != APEXCODEC_STATUS_OK) {
1841 LOG(ERROR) << "FillMemory -- failed to set graphic buffer";
1842 return false;
1843 }
1844 ApexCodec_Buffer_setBufferInfo(apexBuffer, flags, frameIndex, timestampUs);
1845 return true;
1846 } else if (buffer->data().graphicBlocks().size() > 1) {
1847 return false;
1848 }
1849 const C2Handle *handle = buffer->data().graphicBlocks().front().handle();
1850 uint32_t width, height, format, stride, igbp_slot, generation;
1851 uint64_t usage, igbp_id;
1852 _UnwrapNativeCodec2GrallocMetadata(
1853 handle, &width, &height, &format, &usage, &stride, &generation,
1854 &igbp_id, &igbp_slot);
1855 native_handle_t *grallocHandle = UnwrapNativeCodec2GrallocHandle(handle);
1856 sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(
1857 grallocHandle, GraphicBuffer::CLONE_HANDLE,
1858 width, height, format, 1, usage, stride);
1859 native_handle_delete(grallocHandle);
1860 AHardwareBuffer *hardwareBuffer =
1861 AHardwareBuffer_from_GraphicBuffer(graphicBuffer.get());
1862 AHardwareBuffer_acquire(hardwareBuffer);
1863 ApexCodec_Status status = ApexCodec_Buffer_setGraphicBuffer(
1864 apexBuffer, hardwareBuffer);
1865 if (status != APEXCODEC_STATUS_OK) {
1866 LOG(ERROR) << "FillMemory -- failed to set graphic buffer";
1867 return false;
1868 }
1869 ApexCodec_Buffer_setBufferInfo(apexBuffer, flags, frameIndex, timestampUs);
1870 return true;
1871 }
1872 }
1873 return false;
1874 }
1875
1876 ApexCodec_Component *mApexComponent;
1877 std::weak_ptr<Listener> mListener;
1878 std::weak_ptr<Component> mComponent;
1879
1880 std::thread mThread;
1881 std::mutex mMutex;
1882 std::condition_variable mCondition;
1883 bool mStopped;
1884 ApexCodec_BufferType mOutputBufferType;
1885
1886 size_t mLinearBlockCapacity;
1887 uint32_t mWidth;
1888 uint32_t mHeight;
1889 uint32_t mFormat;
1890
1891 std::shared_ptr<C2BlockPool> mBlockPool;
1892 std::list<std::unique_ptr<C2Work>> mWorkQueue;
1893 std::map<uint64_t, std::unique_ptr<C2Work>> mWorkMap;
1894 };
1895
1896 // Codec2Client::Component::HidlBufferPoolSender
1897 struct Codec2Client::Component::HidlBufferPoolSender :
1898 hardware::media::c2::V1_1::utils::DefaultBufferPoolSender {
HidlBufferPoolSenderandroid::Codec2Client::Component::HidlBufferPoolSender1899 HidlBufferPoolSender()
1900 : hardware::media::c2::V1_1::utils::DefaultBufferPoolSender() {
1901 }
1902 };
1903
1904 // Codec2Client::Component::AidlBufferPoolSender
1905 struct Codec2Client::Component::AidlBufferPoolSender :
1906 c2_aidl::utils::DefaultBufferPoolSender {
AidlBufferPoolSenderandroid::Codec2Client::Component::AidlBufferPoolSender1907 AidlBufferPoolSender()
1908 : c2_aidl::utils::DefaultBufferPoolSender() {
1909 }
1910 };
1911
1912 // Codec2Client::Component::OutputBufferQueue
1913 struct Codec2Client::Component::OutputBufferQueue :
1914 hardware::media::c2::OutputBufferQueue {
OutputBufferQueueandroid::Codec2Client::Component::OutputBufferQueue1915 OutputBufferQueue()
1916 : hardware::media::c2::OutputBufferQueue() {
1917 }
1918 };
1919
1920 // The class holds GraphicBufferAllocator and the associated id of
1921 // HAL side BlockPool.
1922 // This is tightly coupled with BlockPool creation and destruction.
1923 // The life cycle inside class will be as follows.
1924 //
1925 // On createBlockPool client request.
1926 // 1. this::create() creates a GraphicBufferAllocator and set it as
1927 // the current.
1928 // 2. C2AIDL_HAL::createBlockPool() creates a C2BlockPool using
1929 // the GraphicBufferAllocator created in #1.
1930 // 3. this::setCurrentId() associates the id returned in #2 to the current
1931 //
1932 // On destroyBlockPool cliet request
1933 // 1. C2AIDL_HAL::destroyBlockPool() destroys the block pool
1934 // from HAL process.
1935 // 2. this::remove() destroys GraphicBufferAllocator which is associatted
1936 // with the C2BlockPool in #1.
1937 //
1938 struct Codec2Client::Component::GraphicBufferAllocators {
1939 private:
1940 std::optional<C2BlockPool::local_id_t> mCurrentId;
1941 std::shared_ptr<AidlGraphicBufferAllocator> mCurrent;
1942
1943 // A new BlockPool is created before the old BlockPool is destroyed.
1944 // This holds the reference of the old BlockPool when a new BlockPool is
1945 // created until the old BlockPool is explicitly requested for destruction.
1946 std::map<C2BlockPool::local_id_t, std::shared_ptr<AidlGraphicBufferAllocator>> mOlds;
1947 std::mutex mMutex;
1948
1949 public:
1950 // Creates a GraphicBufferAllocator which will be passed to HAL
1951 // for creating C2BlockPool. And the created GraphicBufferAllocator
1952 // will be used afterwards by current().
createandroid::Codec2Client::Component::GraphicBufferAllocators1953 std::shared_ptr<AidlGraphicBufferAllocator> create() {
1954 std::unique_lock<std::mutex> l(mMutex);
1955 if (mCurrent) {
1956 // If this is not stopped.
1957 mCurrent->reset();
1958 if (mCurrentId.has_value()) {
1959 mOlds.emplace(mCurrentId.value(), mCurrent);
1960 }
1961 mCurrentId.reset();
1962 mCurrent.reset();
1963 }
1964 // TODO: integrate initial value with CCodec/CCodecBufferChannel
1965 mCurrent =
1966 AidlGraphicBufferAllocator::CreateGraphicBufferAllocator(3 /* maxDequeueCount */);
1967 ALOGD("GraphicBufferAllocator created");
1968 return mCurrent;
1969 }
1970
1971 // Associates the blockpool Id returned from HAL to the
1972 // current GraphicBufferAllocator.
setCurrentIdandroid::Codec2Client::Component::GraphicBufferAllocators1973 void setCurrentId(C2BlockPool::local_id_t id) {
1974 std::unique_lock<std::mutex> l(mMutex);
1975 CHECK(!mCurrentId.has_value());
1976 mCurrentId = id;
1977 }
1978
1979 // Returns the current GraphicBufferAllocator.
currentandroid::Codec2Client::Component::GraphicBufferAllocators1980 std::shared_ptr<AidlGraphicBufferAllocator> current() {
1981 std::unique_lock<std::mutex> l(mMutex);
1982 return mCurrent;
1983 }
1984
1985 // Removes the GraphicBufferAllocator associated with given \p id.
removeandroid::Codec2Client::Component::GraphicBufferAllocators1986 void remove(C2BlockPool::local_id_t id) {
1987 std::unique_lock<std::mutex> l(mMutex);
1988 mOlds.erase(id);
1989 if (mCurrentId == id) {
1990 if (mCurrent) {
1991 mCurrent->reset();
1992 mCurrent.reset();
1993 }
1994 mCurrentId.reset();
1995 }
1996 }
1997 };
1998
1999 // Codec2Client
Codec2Client(sp<HidlBase> const & base,sp<c2_hidl::IConfigurable> const & configurable,size_t serviceIndex)2000 Codec2Client::Codec2Client(sp<HidlBase> const& base,
2001 sp<c2_hidl::IConfigurable> const& configurable,
2002 size_t serviceIndex)
2003 : Configurable{configurable},
2004 mHidlBase1_0{base},
2005 mHidlBase1_1{HidlBase1_1::castFrom(base)},
2006 mHidlBase1_2{HidlBase1_2::castFrom(base)},
2007 mServiceIndex{serviceIndex} {
2008 Return<sp<bufferpool_hidl::IClientManager>> transResult = base->getPoolClientManager();
2009 if (!transResult.isOk()) {
2010 LOG(ERROR) << "getPoolClientManager -- transaction failed.";
2011 } else {
2012 mHidlHostPoolManager = static_cast<sp<bufferpool_hidl::IClientManager>>(transResult);
2013 }
2014 }
2015
Codec2Client(std::shared_ptr<AidlBase> const & base,std::shared_ptr<c2_aidl::IConfigurable> const & configurable,size_t serviceIndex)2016 Codec2Client::Codec2Client(std::shared_ptr<AidlBase> const& base,
2017 std::shared_ptr<c2_aidl::IConfigurable> const& configurable,
2018 size_t serviceIndex)
2019 : Configurable{configurable},
2020 mAidlBase{base},
2021 mServiceIndex{serviceIndex} {
2022 ::ndk::ScopedAStatus transStatus = base->getPoolClientManager(&mAidlHostPoolManager);
2023 if (!transStatus.isOk()) {
2024 LOG(ERROR) << "getPoolClientManager -- transaction failed.";
2025 mAidlHostPoolManager.reset();
2026 }
2027 }
2028
Codec2Client(ApexCodec_ComponentStore * base,size_t serviceIndex)2029 Codec2Client::Codec2Client(ApexCodec_ComponentStore *base,
2030 size_t serviceIndex)
2031 : Configurable{nullptr, "android.componentStore.apexCodecs"},
2032 mApexBase{base},
2033 mServiceIndex{serviceIndex} {
2034 }
2035
getHidlBase() const2036 sp<Codec2Client::HidlBase> const& Codec2Client::getHidlBase() const {
2037 return mHidlBase1_0;
2038 }
2039
getHidlBase1_0() const2040 sp<Codec2Client::HidlBase1_0> const& Codec2Client::getHidlBase1_0() const {
2041 return mHidlBase1_0;
2042 }
2043
getHidlBase1_1() const2044 sp<Codec2Client::HidlBase1_1> const& Codec2Client::getHidlBase1_1() const {
2045 return mHidlBase1_1;
2046 }
2047
getHidlBase1_2() const2048 sp<Codec2Client::HidlBase1_2> const& Codec2Client::getHidlBase1_2() const {
2049 return mHidlBase1_2;
2050 }
2051
getAidlBase() const2052 ::ndk::SpAIBinder Codec2Client::getAidlBase() const {
2053 return mAidlBase ? mAidlBase->asBinder() : nullptr;
2054 }
2055
getServiceName() const2056 std::string const& Codec2Client::getServiceName() const {
2057 return GetServiceNames()[mServiceIndex];
2058 }
2059
createComponent(const C2String & name,const std::shared_ptr<Codec2Client::Listener> & listener,std::shared_ptr<Codec2Client::Component> * const component)2060 c2_status_t Codec2Client::createComponent(
2061 const C2String& name,
2062 const std::shared_ptr<Codec2Client::Listener>& listener,
2063 std::shared_ptr<Codec2Client::Component>* const component) {
2064 if (mApexBase) {
2065 return createComponent_apex(name, listener, component);
2066 } else if (mAidlBase) {
2067 return createComponent_aidl(name, listener, component);
2068 } else {
2069 return createComponent_hidl(name, listener, component);
2070 }
2071 }
2072
createComponent_apex(const C2String & name,const std::shared_ptr<Codec2Client::Listener> & listener,std::shared_ptr<Codec2Client::Component> * const component)2073 c2_status_t Codec2Client::createComponent_apex(
2074 const C2String& name,
2075 const std::shared_ptr<Codec2Client::Listener>& listener,
2076 std::shared_ptr<Codec2Client::Component>* const component) {
2077 if (__builtin_available(android 36, *)) {
2078 ApexCodec_Component *apexComponent = nullptr;
2079 ApexCodec_Status status = ApexCodec_Component_create(
2080 mApexBase, name.c_str(), &apexComponent);
2081 if (status != APEXCODEC_STATUS_OK) {
2082 return (c2_status_t)status;
2083 }
2084 *component = std::make_shared<Codec2Client::Component>(apexComponent, name);
2085 (*component)->initApexHandler(listener, *component);
2086 return C2_OK;
2087 } else {
2088 return C2_OMITTED;
2089 }
2090 }
2091
createComponent_aidl(const C2String & name,const std::shared_ptr<Codec2Client::Listener> & listener,std::shared_ptr<Codec2Client::Component> * const component)2092 c2_status_t Codec2Client::createComponent_aidl(
2093 const C2String& name,
2094 const std::shared_ptr<Codec2Client::Listener>& listener,
2095 std::shared_ptr<Codec2Client::Component>* const component) {
2096 std::shared_ptr<Component::AidlListener> aidlListener =
2097 Component::AidlListener::make<Component::AidlListener>();
2098 aidlListener->base = listener;
2099 std::shared_ptr<c2_aidl::IComponent> aidlComponent;
2100 ::ndk::ScopedAStatus transStatus = mAidlBase->createComponent(
2101 name,
2102 aidlListener,
2103 bufferpool2_aidl::implementation::ClientManager::getInstance(),
2104 &aidlComponent);
2105 c2_status_t status = GetC2Status(transStatus, "createComponent");
2106 if (status != C2_OK) {
2107 return status;
2108 } else if (!aidlComponent) {
2109 LOG(ERROR) << "createComponent(" << name.c_str()
2110 << ") -- null component.";
2111 return C2_CORRUPTED;
2112 }
2113 *component = std::make_shared<Codec2Client::Component>(aidlComponent);
2114 status = (*component)->setDeathListener((*component), listener);
2115 if (status != C2_OK) {
2116 LOG(ERROR) << "createComponent(" << name.c_str()
2117 << ") -- failed to set up death listener: "
2118 << status << ".";
2119 }
2120 (*component)->mAidlBufferPoolSender->setReceiver(mAidlHostPoolManager);
2121 aidlListener->component = *component;
2122 return status;
2123 }
2124
createComponent_hidl(const C2String & name,const std::shared_ptr<Codec2Client::Listener> & listener,std::shared_ptr<Codec2Client::Component> * const component)2125 c2_status_t Codec2Client::createComponent_hidl(
2126 const C2String& name,
2127 const std::shared_ptr<Codec2Client::Listener>& listener,
2128 std::shared_ptr<Codec2Client::Component>* const component) {
2129 c2_status_t status;
2130 sp<Component::HidlListener> hidlListener = new Component::HidlListener{};
2131 hidlListener->base = listener;
2132 Return<void> transStatus;
2133 if (mHidlBase1_2) {
2134 transStatus = mHidlBase1_2->createComponent_1_2(
2135 name,
2136 hidlListener,
2137 bufferpool_hidl::implementation::ClientManager::getInstance(),
2138 [&status, component, hidlListener](
2139 c2_hidl::Status s,
2140 const sp<c2_hidl::IComponent>& c) {
2141 status = static_cast<c2_status_t>(s);
2142 if (status != C2_OK) {
2143 return;
2144 }
2145 *component = std::make_shared<Codec2Client::Component>(c);
2146 hidlListener->component = *component;
2147 });
2148 }
2149 else if (mHidlBase1_1) {
2150 transStatus = mHidlBase1_1->createComponent_1_1(
2151 name,
2152 hidlListener,
2153 bufferpool_hidl::implementation::ClientManager::getInstance(),
2154 [&status, component, hidlListener](
2155 c2_hidl::Status s,
2156 const sp<c2_hidl_base::V1_1::IComponent>& c) {
2157 status = static_cast<c2_status_t>(s);
2158 if (status != C2_OK) {
2159 return;
2160 }
2161 *component = std::make_shared<Codec2Client::Component>(c);
2162 hidlListener->component = *component;
2163 });
2164 } else if (mHidlBase1_0) { // ver1_0
2165 transStatus = mHidlBase1_0->createComponent(
2166 name,
2167 hidlListener,
2168 bufferpool_hidl::implementation::ClientManager::getInstance(),
2169 [&status, component, hidlListener](
2170 c2_hidl::Status s,
2171 const sp<c2_hidl_base::V1_0::IComponent>& c) {
2172 status = static_cast<c2_status_t>(s);
2173 if (status != C2_OK) {
2174 return;
2175 }
2176 *component = std::make_shared<Codec2Client::Component>(c);
2177 hidlListener->component = *component;
2178 });
2179 } else {
2180 status = C2_CORRUPTED;
2181 }
2182 if (!transStatus.isOk()) {
2183 LOG(ERROR) << "createComponent(" << name.c_str()
2184 << ") -- transaction failed.";
2185 return C2_TRANSACTION_FAILED;
2186 } else if (status != C2_OK) {
2187 if (status == C2_NOT_FOUND) {
2188 LOG(VERBOSE) << "createComponent(" << name.c_str()
2189 << ") -- component not found.";
2190 } else {
2191 LOG(ERROR) << "createComponent(" << name.c_str()
2192 << ") -- call failed: " << status << ".";
2193 }
2194 return status;
2195 } else if (!*component) {
2196 LOG(ERROR) << "createComponent(" << name.c_str()
2197 << ") -- null component.";
2198 return C2_CORRUPTED;
2199 }
2200
2201 status = (*component)->setDeathListener(*component, listener);
2202 if (status != C2_OK) {
2203 LOG(ERROR) << "createComponent(" << name.c_str()
2204 << ") -- failed to set up death listener: "
2205 << status << ".";
2206 }
2207
2208 (*component)->mHidlBufferPoolSender->setReceiver(mHidlHostPoolManager);
2209 return status;
2210 }
2211
createInterface(const C2String & name,std::shared_ptr<Codec2Client::Interface> * const interface)2212 c2_status_t Codec2Client::createInterface(
2213 const C2String& name,
2214 std::shared_ptr<Codec2Client::Interface>* const interface) {
2215 if (mAidlBase) {
2216 std::shared_ptr<c2_aidl::IComponentInterface> aidlInterface;
2217 ::ndk::ScopedAStatus transStatus = mAidlBase->createInterface(
2218 name,
2219 &aidlInterface);
2220 c2_status_t status = GetC2Status(transStatus, "createInterface");
2221 if (status != C2_OK) {
2222 return status;
2223 } else if (!aidlInterface) {
2224 LOG(ERROR) << "createInterface(" << name.c_str()
2225 << ") -- null interface.";
2226 return C2_CORRUPTED;
2227 }
2228 interface->reset(new Codec2Client::Interface(aidlInterface));
2229 return C2_OK;
2230 }
2231
2232 c2_status_t status;
2233 Return<void> transStatus = mHidlBase1_0->createInterface(
2234 name,
2235 [&status, interface](
2236 c2_hidl::Status s,
2237 const sp<c2_hidl::IComponentInterface>& i) {
2238 status = static_cast<c2_status_t>(s);
2239 if (status != C2_OK) {
2240 return;
2241 }
2242 *interface = std::make_shared<Interface>(i);
2243 });
2244 if (!transStatus.isOk()) {
2245 LOG(ERROR) << "createInterface(" << name.c_str()
2246 << ") -- transaction failed.";
2247 return C2_TRANSACTION_FAILED;
2248 } else if (status != C2_OK) {
2249 if (status == C2_NOT_FOUND) {
2250 LOG(VERBOSE) << "createInterface(" << name.c_str()
2251 << ") -- component not found.";
2252 } else {
2253 LOG(ERROR) << "createInterface(" << name.c_str()
2254 << ") -- call failed: " << status << ".";
2255 }
2256 return status;
2257 }
2258
2259 return status;
2260 }
2261
createInputSurface(std::shared_ptr<InputSurface> * const inputSurface)2262 c2_status_t Codec2Client::createInputSurface(
2263 std::shared_ptr<InputSurface>* const inputSurface) {
2264 if (mAidlBase) {
2265 // FIXME
2266 return C2_OMITTED;
2267 }
2268
2269 c2_status_t status;
2270 Return<void> transStatus = mHidlBase1_0->createInputSurface(
2271 [&status, inputSurface](
2272 c2_hidl::Status s,
2273 const sp<c2_hidl::IInputSurface>& i) {
2274 status = static_cast<c2_status_t>(s);
2275 if (status != C2_OK) {
2276 return;
2277 }
2278 *inputSurface = std::make_shared<InputSurface>(i);
2279 });
2280 if (!transStatus.isOk()) {
2281 LOG(ERROR) << "createInputSurface -- transaction failed.";
2282 return C2_TRANSACTION_FAILED;
2283 } else if (status != C2_OK) {
2284 LOG(DEBUG) << "createInputSurface -- call failed: "
2285 << status << ".";
2286 }
2287 return status;
2288 }
2289
listComponents() const2290 std::vector<C2Component::Traits> const& Codec2Client::listComponents() const {
2291 return Cache::List()[mServiceIndex].getTraits();
2292 }
2293
_listComponents(bool * success) const2294 std::vector<C2Component::Traits> Codec2Client::_listComponents(
2295 bool* success) const {
2296 std::vector<C2Component::Traits> traits;
2297 std::string const& serviceName = getServiceName();
2298
2299 if (mAidlBase) {
2300 std::vector<c2_aidl::IComponentStore::ComponentTraits> aidlTraits;
2301 ::ndk::ScopedAStatus transStatus = mAidlBase->listComponents(&aidlTraits);
2302 if (!transStatus.isOk()) {
2303 LOG(ERROR) << "_listComponents -- transaction failed.";
2304 *success = false;
2305 } else {
2306 traits.resize(aidlTraits.size());
2307 *success = true;
2308 for (size_t i = 0; i < aidlTraits.size(); ++i) {
2309 if (!c2_aidl::utils::FromAidl(&traits[i], aidlTraits[i])) {
2310 LOG(ERROR) << "_listComponents -- corrupted output.";
2311 *success = false;
2312 traits.clear();
2313 break;
2314 }
2315 traits[i].owner = serviceName;
2316 }
2317 }
2318 return traits;
2319 }
2320 Return<void> transStatus = mHidlBase1_0->listComponents(
2321 [&traits, &serviceName](c2_hidl::Status s,
2322 const hidl_vec<c2_hidl::IComponentStore::ComponentTraits>& t) {
2323 if (s != c2_hidl::Status::OK) {
2324 LOG(DEBUG) << "_listComponents -- call failed: "
2325 << static_cast<c2_status_t>(s) << ".";
2326 return;
2327 }
2328 traits.resize(t.size());
2329 for (size_t i = 0; i < t.size(); ++i) {
2330 if (!c2_hidl::utils::objcpy(&traits[i], t[i])) {
2331 LOG(ERROR) << "_listComponents -- corrupted output.";
2332 return;
2333 }
2334 traits[i].owner = serviceName;
2335 }
2336 });
2337 if (!transStatus.isOk()) {
2338 LOG(ERROR) << "_listComponents -- transaction failed.";
2339 *success = false;
2340 } else {
2341 *success = true;
2342 }
2343 return traits;
2344 }
2345
copyBuffer(const std::shared_ptr<C2Buffer> & src,const std::shared_ptr<C2Buffer> & dst)2346 c2_status_t Codec2Client::copyBuffer(
2347 const std::shared_ptr<C2Buffer>& src,
2348 const std::shared_ptr<C2Buffer>& dst) {
2349 // TODO: Implement?
2350 (void)src;
2351 (void)dst;
2352 LOG(ERROR) << "copyBuffer not implemented";
2353 return C2_OMITTED;
2354 }
2355
getParamReflector()2356 std::shared_ptr<C2ParamReflector> Codec2Client::getParamReflector() {
2357 // TODO: this is not meant to be exposed as C2ParamReflector on the client side; instead, it
2358 // should reflect the HAL API.
2359 struct HidlSimpleParamReflector : public C2ParamReflector {
2360 std::unique_ptr<C2StructDescriptor> describe(
2361 C2Param::CoreIndex coreIndex) const override {
2362 hidl_vec<c2_hidl::ParamIndex> indices(1);
2363 indices[0] = static_cast<c2_hidl::ParamIndex>(coreIndex.coreIndex());
2364 std::unique_ptr<C2StructDescriptor> descriptor;
2365 Return<void> transStatus = mBase->getStructDescriptors(
2366 indices,
2367 [&descriptor](
2368 c2_hidl::Status s,
2369 const hidl_vec<c2_hidl::StructDescriptor>& sd) {
2370 c2_status_t status = static_cast<c2_status_t>(s);
2371 if (status != C2_OK) {
2372 LOG(DEBUG) << "SimpleParamReflector -- "
2373 "getStructDescriptors() failed: "
2374 << status << ".";
2375 descriptor.reset();
2376 return;
2377 }
2378 if (sd.size() != 1) {
2379 LOG(DEBUG) << "SimpleParamReflector -- "
2380 "getStructDescriptors() "
2381 "returned vector of size "
2382 << sd.size() << ". "
2383 "It should be 1.";
2384 descriptor.reset();
2385 return;
2386 }
2387 if (!c2_hidl::utils::objcpy(&descriptor, sd[0])) {
2388 LOG(DEBUG) << "SimpleParamReflector -- "
2389 "getStructDescriptors() returned "
2390 "corrupted data.";
2391 descriptor.reset();
2392 return;
2393 }
2394 });
2395 if (!transStatus.isOk()) {
2396 LOG(DEBUG) << "SimpleParamReflector -- transaction failed: "
2397 << transStatus.description();
2398 descriptor.reset();
2399 }
2400 return descriptor;
2401 }
2402
2403 HidlSimpleParamReflector(sp<HidlBase> base)
2404 : mBase(base) { }
2405
2406 sp<HidlBase> mBase;
2407 };
2408 struct AidlSimpleParamReflector : public C2ParamReflector {
2409 std::unique_ptr<C2StructDescriptor> describe(
2410 C2Param::CoreIndex coreIndex) const override {
2411 std::vector<c2_aidl::StructDescriptor> aidlDesc;
2412 std::unique_ptr<C2StructDescriptor> descriptor;
2413 ::ndk::ScopedAStatus transStatus = mBase->getStructDescriptors(
2414 {int32_t(coreIndex.coreIndex())},
2415 &aidlDesc);
2416 c2_status_t status = GetC2Status(transStatus, "describe");
2417 if (status != C2_OK) {
2418 descriptor.reset();
2419 } else if (!c2_aidl::utils::FromAidl(&descriptor, aidlDesc[0])) {
2420 LOG(ERROR) << "describe -- conversion failed.";
2421 descriptor.reset();
2422 }
2423 return descriptor;
2424 }
2425
2426 AidlSimpleParamReflector(const std::shared_ptr<AidlBase> &base)
2427 : mBase(base) { }
2428
2429 std::shared_ptr<AidlBase> mBase;
2430 };
2431
2432 if (mAidlBase) {
2433 return std::make_shared<AidlSimpleParamReflector>(mAidlBase);
2434 }
2435 return std::make_shared<HidlSimpleParamReflector>(mHidlBase1_0);
2436 };
2437
CacheServiceNames()2438 std::vector<std::string> Codec2Client::CacheServiceNames() {
2439 std::vector<std::string> names;
2440
2441 if (c2_aidl::utils::IsSelected()) {
2442 if (__builtin_available(android __ANDROID_API_S__, *)) {
2443 // Get AIDL service names
2444 AServiceManager_forEachDeclaredInstance(
2445 AidlBase::descriptor, &names, [](const char *name, void *context) {
2446 std::vector<std::string> *names = (std::vector<std::string> *)context;
2447 names->emplace_back(name);
2448 });
2449 } else {
2450 LOG(FATAL) << "C2 AIDL cannot be selected on Android version older than 35";
2451 }
2452 } else {
2453 // Get HIDL service names
2454 using ::android::hardware::media::c2::V1_0::IComponentStore;
2455 using ::android::hidl::manager::V1_2::IServiceManager;
2456 while (true) {
2457 sp<IServiceManager> serviceManager = IServiceManager::getService();
2458 CHECK(serviceManager) << "Hardware service manager is not running.";
2459
2460 Return<void> transResult;
2461 transResult = serviceManager->listManifestByInterface(
2462 IComponentStore::descriptor,
2463 [&names](
2464 hidl_vec<hidl_string> const& instanceNames) {
2465 names.insert(names.end(), instanceNames.begin(), instanceNames.end());
2466 });
2467 if (transResult.isOk()) {
2468 break;
2469 }
2470 LOG(ERROR) << "Could not retrieve the list of service instances of "
2471 << IComponentStore::descriptor
2472 << ". Retrying...";
2473 }
2474 }
2475 // Sort service names in each category.
2476 std::stable_sort(
2477 names.begin(), names.end(),
2478 [](const std::string &a, const std::string &b) {
2479 // First compare by prefix: default -> vendor -> {everything else}
2480 constexpr int DEFAULT = 1;
2481 constexpr int VENDOR = 2;
2482 constexpr int OTHER = 3;
2483 int aPrefix = ((a.compare(0, 7, "default") == 0) ? DEFAULT :
2484 (a.compare(0, 6, "vendor") == 0) ? VENDOR :
2485 OTHER);
2486 int bPrefix = ((b.compare(0, 7, "default") == 0) ? DEFAULT :
2487 (b.compare(0, 6, "vendor") == 0) ? VENDOR :
2488 OTHER);
2489 if (aPrefix != bPrefix) {
2490 return aPrefix < bPrefix;
2491 }
2492 // If the prefix is the same, compare alphabetically
2493 return a < b;
2494 });
2495
2496 if (__builtin_available(android 36, *)) {
2497 if (android::media::codec::provider_->in_process_sw_audio_codec_support()
2498 && nullptr != ApexCodec_GetComponentStore()) {
2499 names.push_back("__ApexCodecs__");
2500 }
2501 }
2502
2503 // Summarize to logcat.
2504 if (names.empty()) {
2505 LOG(INFO) << "No Codec2 services declared in the manifest.";
2506 } else {
2507 std::stringstream stringOutput;
2508 stringOutput << "Available Codec2 services:";
2509 for (std::string const& name : names) {
2510 stringOutput << " \"" << name << "\"";
2511 }
2512 LOG(INFO) << stringOutput.str();
2513 }
2514
2515 return names;
2516 }
2517
GetServiceNames()2518 std::vector<std::string> const& Codec2Client::GetServiceNames() {
2519 static std::vector<std::string> sServiceNames = CacheServiceNames();
2520 return sServiceNames;
2521 }
2522
CreateFromService(const char * name,bool setAsPreferredCodec2ComponentStore)2523 std::shared_ptr<Codec2Client> Codec2Client::CreateFromService(
2524 const char* name,
2525 bool setAsPreferredCodec2ComponentStore) {
2526 size_t index = getServiceIndex(name);
2527 if (index == GetServiceNames().size()) {
2528 if (setAsPreferredCodec2ComponentStore) {
2529 LOG(WARNING) << "CreateFromService(" << name
2530 << ") -- preferred C2ComponentStore not set.";
2531 }
2532 return nullptr;
2533 }
2534 std::shared_ptr<Codec2Client> client = _CreateFromIndex(index);
2535 if (setAsPreferredCodec2ComponentStore) {
2536 SetPreferredCodec2ComponentStore(
2537 std::make_shared<Client2Store>(client));
2538 LOG(INFO) << "CreateFromService(" << name
2539 << ") -- service set as preferred C2ComponentStore.";
2540 }
2541 return client;
2542 }
2543
2544 std::vector<std::shared_ptr<Codec2Client>> Codec2Client::
CreateFromAllServices()2545 CreateFromAllServices() {
2546 std::vector<std::shared_ptr<Codec2Client>> clients(
2547 GetServiceNames().size());
2548 for (size_t i = GetServiceNames().size(); i > 0; ) {
2549 --i;
2550 clients[i] = _CreateFromIndex(i);
2551 }
2552 return clients;
2553 }
2554
_CreateFromIndex(size_t index)2555 std::shared_ptr<Codec2Client> Codec2Client::_CreateFromIndex(size_t index) {
2556 std::string const& name = GetServiceNames()[index];
2557 LOG(VERBOSE) << "Creating a Codec2 client to service \"" << name << "\"";
2558
2559 if (name == "__ApexCodecs__") {
2560 if (__builtin_available(android 36, *)) {
2561 return std::make_shared<Codec2Client>(ApexCodec_GetComponentStore(), index);
2562 } else {
2563 LOG(FATAL) << "ApexCodecs not supported on Android version older than 36";
2564 }
2565 } else if (c2_aidl::utils::IsSelected()) {
2566 if (__builtin_available(android __ANDROID_API_S__, *)) {
2567 std::string instanceName =
2568 ::android::base::StringPrintf("%s/%s", AidlBase::descriptor, name.c_str());
2569 if (AServiceManager_isDeclared(instanceName.c_str())) {
2570 std::shared_ptr<AidlBase> baseStore = AidlBase::fromBinder(
2571 ::ndk::SpAIBinder(AServiceManager_waitForService(instanceName.c_str())));
2572 CHECK(baseStore) << "Codec2 AIDL service \"" << name << "\""
2573 " inaccessible for unknown reasons.";
2574 LOG(VERBOSE) << "Client to Codec2 AIDL service \"" << name << "\" created";
2575 std::shared_ptr<c2_aidl::IConfigurable> configurable;
2576 ::ndk::ScopedAStatus transStatus = baseStore->getConfigurable(&configurable);
2577 CHECK(transStatus.isOk()) << "Codec2 AIDL service \"" << name << "\""
2578 "does not have IConfigurable.";
2579 return std::make_shared<Codec2Client>(baseStore, configurable, index);
2580 } else {
2581 LOG(ERROR) << "Codec2 AIDL service \"" << name << "\" is not declared";
2582 }
2583 } else {
2584 LOG(FATAL) << "C2 AIDL cannot be selected on Android version older than 35";
2585 }
2586 } else {
2587 std::string instanceName = "android.hardware.media.c2/" + name;
2588 sp<HidlBase> baseStore = HidlBase::getService(name);
2589 CHECK(baseStore) << "Codec2 service \"" << name << "\""
2590 " inaccessible for unknown reasons.";
2591 LOG(VERBOSE) << "Client to Codec2 service \"" << name << "\" created";
2592 Return<sp<c2_hidl::IConfigurable>> transResult = baseStore->getConfigurable();
2593 CHECK(transResult.isOk()) << "Codec2 service \"" << name << "\""
2594 "does not have IConfigurable.";
2595 sp<c2_hidl::IConfigurable> configurable =
2596 static_cast<sp<c2_hidl::IConfigurable>>(transResult);
2597 return std::make_shared<Codec2Client>(baseStore, configurable, index);
2598 }
2599 return nullptr;
2600 }
2601
ForAllServices(const std::string & key,size_t numberOfAttempts,std::function<c2_status_t (const std::shared_ptr<Codec2Client> &)> predicate)2602 c2_status_t Codec2Client::ForAllServices(
2603 const std::string &key,
2604 size_t numberOfAttempts,
2605 std::function<c2_status_t(const std::shared_ptr<Codec2Client>&)>
2606 predicate) {
2607 c2_status_t status = C2_NO_INIT; // no IComponentStores present
2608
2609 // Cache the mapping key -> index of Codec2Client in Cache::List().
2610 static std::mutex key2IndexMutex;
2611 static std::map<std::string, size_t> key2Index;
2612
2613 // By default try all stores. However, try the last known client first. If
2614 // the last known client fails, retry once. We do this by pushing the last
2615 // known client in front of the list of all clients.
2616 std::deque<size_t> indices;
2617 for (size_t index = Cache::List().size(); index > 0; ) {
2618 indices.push_front(--index);
2619 }
2620
2621 bool wasMapped = false;
2622 {
2623 std::scoped_lock lock{key2IndexMutex};
2624 auto it = key2Index.find(key);
2625 if (it != key2Index.end()) {
2626 indices.push_front(it->second);
2627 wasMapped = true;
2628 }
2629 }
2630
2631 for (size_t index : indices) {
2632 Cache& cache = Cache::List()[index];
2633 for (size_t tries = numberOfAttempts; tries > 0; --tries) {
2634 std::shared_ptr<Codec2Client> client{cache.getClient()};
2635 status = predicate(client);
2636 if (status == C2_OK) {
2637 std::scoped_lock lock{key2IndexMutex};
2638 key2Index[key] = index; // update last known client index
2639 return C2_OK;
2640 } else if (status == C2_NO_MEMORY) {
2641 return C2_NO_MEMORY;
2642 } else if (status == C2_TRANSACTION_FAILED) {
2643 LOG(WARNING) << "\"" << key << "\" failed for service \""
2644 << client->getName()
2645 << "\" due to transaction failure. "
2646 << "(Service may have crashed.)"
2647 << (tries > 1 ? " Retrying..." : "");
2648 cache.invalidate();
2649 continue;
2650 }
2651 if (wasMapped) {
2652 LOG(INFO) << "\"" << key << "\" became invalid in service \""
2653 << client->getName() << "\". Retrying...";
2654 wasMapped = false;
2655 }
2656 break;
2657 }
2658 }
2659 return status; // return the last status from a valid client
2660 }
2661
CreateComponentByName(const char * componentName,const std::shared_ptr<Listener> & listener,std::shared_ptr<Component> * component,std::shared_ptr<Codec2Client> * owner,size_t numberOfAttempts)2662 c2_status_t Codec2Client::CreateComponentByName(
2663 const char* componentName,
2664 const std::shared_ptr<Listener>& listener,
2665 std::shared_ptr<Component>* component,
2666 std::shared_ptr<Codec2Client>* owner,
2667 size_t numberOfAttempts) {
2668 std::string key{"create:"};
2669 key.append(componentName);
2670 c2_status_t status = ForAllServices(
2671 key,
2672 numberOfAttempts,
2673 [owner, component, componentName, &listener](
2674 const std::shared_ptr<Codec2Client> &client)
2675 -> c2_status_t {
2676 c2_status_t status = client->createComponent(componentName,
2677 listener,
2678 component);
2679 if (status == C2_OK) {
2680 if (owner) {
2681 *owner = client;
2682 }
2683 } else if (status != C2_NOT_FOUND) {
2684 LOG(DEBUG) << "IComponentStore("
2685 << client->getServiceName()
2686 << ")::createComponent(\"" << componentName
2687 << "\") returned status = "
2688 << status << ".";
2689 }
2690 return status;
2691 });
2692 if (status != C2_OK) {
2693 LOG(DEBUG) << "Failed to create component \"" << componentName
2694 << "\" from all known services. "
2695 "Last returned status = " << status << ".";
2696 }
2697 return status;
2698 }
2699
CreateInterfaceByName(const char * interfaceName,std::shared_ptr<Codec2Client> * owner,size_t numberOfAttempts)2700 std::shared_ptr<Codec2Client::Interface> Codec2Client::CreateInterfaceByName(
2701 const char* interfaceName,
2702 std::shared_ptr<Codec2Client>* owner,
2703 size_t numberOfAttempts) {
2704 std::string key{"create:"};
2705 key.append(interfaceName);
2706 std::shared_ptr<Interface> interface;
2707 c2_status_t status = ForAllServices(
2708 key,
2709 numberOfAttempts,
2710 [owner, &interface, interfaceName](
2711 const std::shared_ptr<Codec2Client> &client)
2712 -> c2_status_t {
2713 c2_status_t status = client->createInterface(interfaceName,
2714 &interface);
2715 if (status == C2_OK) {
2716 if (owner) {
2717 *owner = client;
2718 }
2719 } else if (status != C2_NOT_FOUND) {
2720 LOG(DEBUG) << "IComponentStore("
2721 << client->getServiceName()
2722 << ")::createInterface(\"" << interfaceName
2723 << "\") returned status = "
2724 << status << ".";
2725 }
2726 return status;
2727 });
2728 if (status != C2_OK) {
2729 LOG(DEBUG) << "Failed to create interface \"" << interfaceName
2730 << "\" from all known services. "
2731 "Last returned status = " << status << ".";
2732 }
2733 return interface;
2734 }
2735
ListComponents()2736 std::vector<C2Component::Traits> const& Codec2Client::ListComponents() {
2737 static std::vector<C2Component::Traits> sList{[]() {
2738 std::vector<C2Component::Traits> list;
2739 for (Cache& cache : Cache::List()) {
2740 std::vector<C2Component::Traits> const& traits = cache.getTraits();
2741 list.insert(list.end(), traits.begin(), traits.end());
2742 }
2743 return list;
2744 }()};
2745 return sList;
2746 }
2747
CreateInputSurface(char const * serviceName)2748 std::shared_ptr<Codec2Client::InputSurface> Codec2Client::CreateInputSurface(
2749 char const* serviceName) {
2750 if (!IsCodec2AidlInputSurfaceSelected()) {
2751 return nullptr;
2752 }
2753 size_t index = GetServiceNames().size();
2754 if (serviceName) {
2755 index = getServiceIndex(serviceName);
2756 if (index == GetServiceNames().size()) {
2757 LOG(DEBUG) << "CreateInputSurface -- invalid service name: \""
2758 << serviceName << "\"";
2759 }
2760 }
2761
2762 std::shared_ptr<Codec2Client::InputSurface> inputSurface;
2763 if (index != GetServiceNames().size()) {
2764 std::shared_ptr<Codec2Client> client = Cache::List()[index].getClient();
2765 if (client->createInputSurface(&inputSurface) == C2_OK) {
2766 return inputSurface;
2767 }
2768 }
2769 LOG(INFO) << "CreateInputSurface -- attempting to create an input surface "
2770 "from all services...";
2771 for (Cache& cache : Cache::List()) {
2772 std::shared_ptr<Codec2Client> client = cache.getClient();
2773 if (client->createInputSurface(&inputSurface) == C2_OK) {
2774 LOG(INFO) << "CreateInputSurface -- input surface obtained from "
2775 "service \"" << client->getServiceName() << "\"";
2776 return inputSurface;
2777 }
2778 }
2779 LOG(WARNING) << "CreateInputSurface -- failed to create an input surface "
2780 "from all services";
2781 return nullptr;
2782 }
2783
IsAidlSelected()2784 bool Codec2Client::IsAidlSelected() {
2785 return c2_aidl::utils::IsSelected();
2786 }
2787
2788 // Codec2Client::Interface
Interface(const sp<HidlBase> & base)2789 Codec2Client::Interface::Interface(const sp<HidlBase>& base)
2790 : Configurable{
2791 [base]() -> sp<c2_hidl::IConfigurable> {
2792 Return<sp<c2_hidl::IConfigurable>> transResult =
2793 base->getConfigurable();
2794 return transResult.isOk() ?
2795 static_cast<sp<c2_hidl::IConfigurable>>(transResult) :
2796 nullptr;
2797 }()
2798 },
2799 mHidlBase{base} {
2800 }
2801
Interface(const std::shared_ptr<AidlBase> & base)2802 Codec2Client::Interface::Interface(const std::shared_ptr<AidlBase>& base)
2803 : Configurable{
2804 [base]() -> std::shared_ptr<c2_aidl::IConfigurable> {
2805 std::shared_ptr<c2_aidl::IConfigurable> aidlConfigurable;
2806 ::ndk::ScopedAStatus transStatus =
2807 base->getConfigurable(&aidlConfigurable);
2808 return transStatus.isOk() ? aidlConfigurable : nullptr;
2809 }()
2810 },
2811 mAidlBase{base} {
2812 }
2813
2814 // Codec2Client::Component
2815
2816 class Codec2Client::Component::AidlDeathManager {
2817 public:
AidlDeathManager()2818 AidlDeathManager()
2819 : mSeq(0),
2820 mDeathRecipient(AIBinder_DeathRecipient_new(OnBinderDied)) {
2821 }
2822
2823 ~AidlDeathManager() = default;
2824
linkToDeath(const std::shared_ptr<Component> & comp,const std::shared_ptr<Listener> & listener,size_t * seqPtr)2825 bool linkToDeath(
2826 const std::shared_ptr<Component> &comp,
2827 const std::shared_ptr<Listener> &listener,
2828 size_t *seqPtr) {
2829 std::unique_lock lock(mMutex);
2830 size_t seq = mSeq++;
2831 if (!mMap.try_emplace(seq, comp, listener).second) {
2832 return false;
2833 }
2834 if (STATUS_OK != AIBinder_linkToDeath(
2835 comp->mAidlBase->asBinder().get(), mDeathRecipient.get(), (void *)seq)) {
2836 mMap.erase(seq);
2837 return false;
2838 }
2839 *seqPtr = seq;
2840 return true;
2841 }
2842
unlinkToDeath(size_t seq,const std::shared_ptr<AidlBase> & base)2843 void unlinkToDeath(size_t seq, const std::shared_ptr<AidlBase> &base) {
2844 std::unique_lock lock(mMutex);
2845 AIBinder_unlinkToDeath(base->asBinder().get(), mDeathRecipient.get(), (void *)seq);
2846 mMap.erase(seq);
2847 }
2848
2849 private:
2850 std::mutex mMutex;
2851 size_t mSeq;
2852 typedef std::tuple<std::weak_ptr<Component>, std::weak_ptr<Listener>> Context;
2853 std::map<size_t, Context> mMap;
2854 ::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
2855
extractContext(size_t seq,Context * context)2856 bool extractContext(size_t seq, Context *context) {
2857 std::unique_lock lock(mMutex);
2858 auto node = mMap.extract(seq);
2859 if (!node) {
2860 return false;
2861 }
2862 *context = node.mapped();
2863 return true;
2864 }
2865
OnBinderDied(void * cookie)2866 static void OnBinderDied(void *cookie) {
2867 size_t seq = size_t(cookie);
2868 Context context;
2869 if (!Component::GetAidlDeathManager()->extractContext(seq, &context)) {
2870 return;
2871 }
2872 std::weak_ptr<Component> weakComponent;
2873 std::weak_ptr<Listener> weakListener;
2874 std::tie(weakComponent, weakListener) = context;
2875 if (std::shared_ptr<Listener> listener = weakListener.lock()) {
2876 listener->onDeath(weakComponent);
2877 } else {
2878 LOG(DEBUG) << "onDeath -- listener died.";
2879 }
2880 }
2881 };
2882
Component(const sp<HidlBase> & base)2883 Codec2Client::Component::Component(const sp<HidlBase>& base)
2884 : Configurable{
2885 [base]() -> sp<c2_hidl::IConfigurable> {
2886 Return<sp<c2_hidl::IComponentInterface>> transResult1 =
2887 base->getInterface();
2888 if (!transResult1.isOk()) {
2889 return nullptr;
2890 }
2891 Return<sp<c2_hidl::IConfigurable>> transResult2 =
2892 static_cast<sp<c2_hidl::IComponentInterface>>(transResult1)->
2893 getConfigurable();
2894 return transResult2.isOk() ?
2895 static_cast<sp<c2_hidl::IConfigurable>>(transResult2) :
2896 nullptr;
2897 }()
2898 },
2899 mHidlBase1_0{base},
2900 mHidlBase1_1{HidlBase1_1::castFrom(base)},
2901 mHidlBase1_2{HidlBase1_2::castFrom(base)},
2902 mHidlBufferPoolSender{std::make_unique<HidlBufferPoolSender>()},
2903 mOutputBufferQueue{std::make_unique<OutputBufferQueue>()} {
2904 }
2905
Component(const sp<HidlBase1_1> & base)2906 Codec2Client::Component::Component(const sp<HidlBase1_1>& base)
2907 : Configurable{
2908 [base]() -> sp<c2_hidl::IConfigurable> {
2909 Return<sp<c2_hidl::IComponentInterface>> transResult1 =
2910 base->getInterface();
2911 if (!transResult1.isOk()) {
2912 return nullptr;
2913 }
2914 Return<sp<c2_hidl::IConfigurable>> transResult2 =
2915 static_cast<sp<c2_hidl::IComponentInterface>>(transResult1)->
2916 getConfigurable();
2917 return transResult2.isOk() ?
2918 static_cast<sp<c2_hidl::IConfigurable>>(transResult2) :
2919 nullptr;
2920 }()
2921 },
2922 mHidlBase1_0{base},
2923 mHidlBase1_1{base},
2924 mHidlBase1_2{HidlBase1_2::castFrom(base)},
2925 mHidlBufferPoolSender{std::make_unique<HidlBufferPoolSender>()},
2926 mOutputBufferQueue{std::make_unique<OutputBufferQueue>()} {
2927 }
2928
Component(const sp<HidlBase1_2> & base)2929 Codec2Client::Component::Component(const sp<HidlBase1_2>& base)
2930 : Configurable{
2931 [base]() -> sp<c2_hidl::IConfigurable> {
2932 Return<sp<c2_hidl::IComponentInterface>> transResult1 =
2933 base->getInterface();
2934 if (!transResult1.isOk()) {
2935 return nullptr;
2936 }
2937 Return<sp<c2_hidl::IConfigurable>> transResult2 =
2938 static_cast<sp<c2_hidl::IComponentInterface>>(transResult1)->
2939 getConfigurable();
2940 return transResult2.isOk() ?
2941 static_cast<sp<c2_hidl::IConfigurable>>(transResult2) :
2942 nullptr;
2943 }()
2944 },
2945 mHidlBase1_0{base},
2946 mHidlBase1_1{base},
2947 mHidlBase1_2{base},
2948 mHidlBufferPoolSender{std::make_unique<HidlBufferPoolSender>()},
2949 mOutputBufferQueue{std::make_unique<OutputBufferQueue>()} {
2950 }
2951
Component(const std::shared_ptr<AidlBase> & base)2952 Codec2Client::Component::Component(const std::shared_ptr<AidlBase> &base)
2953 : Configurable{
2954 [base]() -> std::shared_ptr<c2_aidl::IConfigurable> {
2955 std::shared_ptr<c2_aidl::IComponentInterface> aidlIntf;
2956 ::ndk::ScopedAStatus transStatus = base->getInterface(&aidlIntf);
2957 if (!transStatus.isOk()) {
2958 return nullptr;
2959 }
2960 std::shared_ptr<c2_aidl::IConfigurable> aidlConfigurable;
2961 transStatus = aidlIntf->getConfigurable(&aidlConfigurable);
2962 return transStatus.isOk() ? aidlConfigurable : nullptr;
2963 }()
2964 },
2965 mAidlBase{base},
2966 mAidlBufferPoolSender{std::make_unique<AidlBufferPoolSender>()},
2967 mGraphicBufferAllocators{std::make_unique<GraphicBufferAllocators>()} {
2968 }
2969
Component(ApexCodec_Component * base,const C2String & name)2970 Codec2Client::Component::Component(ApexCodec_Component *base, const C2String &name)
2971 : Configurable{[base]() -> ApexCodec_Configurable * {
2972 if (__builtin_available(android 36, *)) {
2973 return ApexCodec_Component_getConfigurable(base);
2974 } else {
2975 return nullptr;
2976 }
2977 }(), name},
2978 mApexBase{base} {
2979 }
2980
~Component()2981 Codec2Client::Component::~Component() {
2982 if (mAidlDeathSeq) {
2983 GetAidlDeathManager()->unlinkToDeath(*mAidlDeathSeq, mAidlBase);
2984 }
2985 if (mApexBase) {
2986 if (__builtin_available(android 36, *)) {
2987 ApexCodec_Component_destroy(mApexBase);
2988 }
2989 mApexBase = nullptr;
2990 }
2991 }
2992
createBlockPool(C2Allocator::id_t id,C2BlockPool::local_id_t * blockPoolId,std::shared_ptr<Codec2Client::Configurable> * configurable)2993 c2_status_t Codec2Client::Component::createBlockPool(
2994 C2Allocator::id_t id,
2995 C2BlockPool::local_id_t* blockPoolId,
2996 std::shared_ptr<Codec2Client::Configurable>* configurable) {
2997 if (mApexBase) {
2998 std::shared_ptr<C2BlockPool> blockPool;
2999 CreateCodec2BlockPool(id, nullptr, &blockPool);
3000 *blockPoolId = blockPool->getLocalId();
3001 *configurable = nullptr;
3002 mBlockPools[*blockPoolId] = blockPool;
3003 return C2_OK;
3004 }
3005 if (mAidlBase) {
3006 c2_aidl::IComponent::BlockPool aidlBlockPool;
3007 c2_status_t status = C2_OK;
3008
3009 // TODO: Temporary mapping for the current CCodecBufferChannel.
3010 // Handle this properly and remove this temporary allocator mapping.
3011 id = id == C2PlatformAllocatorStore::BUFFERQUEUE ?
3012 C2PlatformAllocatorStore::IGBA : id;
3013
3014 c2_aidl::IComponent::BlockPoolAllocator allocator;
3015 allocator.allocatorId = id;
3016 if (id == C2PlatformAllocatorStore::IGBA) {
3017 std::shared_ptr<AidlGraphicBufferAllocator> gba =
3018 mGraphicBufferAllocators->create();
3019 ::ndk::ScopedFileDescriptor waitableFd;
3020 ::ndk::ScopedAStatus ret = gba->getWaitableFd(&waitableFd);
3021 status = GetC2Status(ret, "Gba::getWaitableFd");
3022 if (status != C2_OK) {
3023 return status;
3024 }
3025 c2_aidl::IComponent::GbAllocator gbAllocator;
3026 gbAllocator.waitableFd = std::move(waitableFd);
3027 gbAllocator.igba =
3028 c2_aidl::IGraphicBufferAllocator::fromBinder(gba->asBinder());
3029 allocator.gbAllocator = std::move(gbAllocator);
3030 ::ndk::ScopedAStatus transStatus = mAidlBase->createBlockPool(
3031 allocator, &aidlBlockPool);
3032 status = GetC2Status(transStatus, "createBlockPool");
3033 if (status != C2_OK) {
3034 return status;
3035 }
3036 mGraphicBufferAllocators->setCurrentId(aidlBlockPool.blockPoolId);
3037 } else {
3038 ::ndk::ScopedAStatus transStatus = mAidlBase->createBlockPool(
3039 allocator, &aidlBlockPool);
3040 status = GetC2Status(transStatus, "createBlockPool");
3041 if (status != C2_OK) {
3042 return status;
3043 }
3044 }
3045 *blockPoolId = aidlBlockPool.blockPoolId;
3046 *configurable = std::make_shared<Configurable>(aidlBlockPool.configurable);
3047 return C2_OK;
3048 }
3049 c2_status_t status;
3050 Return<void> transStatus = mHidlBase1_0->createBlockPool(
3051 static_cast<uint32_t>(id),
3052 [&status, blockPoolId, configurable](
3053 c2_hidl::Status s,
3054 uint64_t pId,
3055 const sp<c2_hidl::IConfigurable>& c) {
3056 status = static_cast<c2_status_t>(s);
3057 configurable->reset();
3058 if (status != C2_OK) {
3059 LOG(DEBUG) << "createBlockPool -- call failed: "
3060 << status << ".";
3061 return;
3062 }
3063 *blockPoolId = static_cast<C2BlockPool::local_id_t>(pId);
3064 *configurable = std::make_shared<Configurable>(c);
3065 });
3066 if (!transStatus.isOk()) {
3067 LOG(ERROR) << "createBlockPool -- transaction failed.";
3068 return C2_TRANSACTION_FAILED;
3069 }
3070 return status;
3071 }
3072
destroyBlockPool(C2BlockPool::local_id_t localId)3073 c2_status_t Codec2Client::Component::destroyBlockPool(
3074 C2BlockPool::local_id_t localId) {
3075 if (mApexBase) {
3076 mBlockPools.erase(localId);
3077 return C2_OK;
3078 }
3079 if (mAidlBase) {
3080 mGraphicBufferAllocators->remove(localId);
3081 ::ndk::ScopedAStatus transStatus = mAidlBase->destroyBlockPool(localId);
3082 return GetC2Status(transStatus, "destroyBlockPool");
3083 }
3084 Return<c2_hidl::Status> transResult = mHidlBase1_0->destroyBlockPool(
3085 static_cast<uint64_t>(localId));
3086 if (!transResult.isOk()) {
3087 LOG(ERROR) << "destroyBlockPool -- transaction failed.";
3088 return C2_TRANSACTION_FAILED;
3089 }
3090 return static_cast<c2_status_t>(static_cast<c2_hidl::Status>(transResult));
3091 }
3092
handleOnWorkDone(const std::list<std::unique_ptr<C2Work>> & workItems)3093 void Codec2Client::Component::handleOnWorkDone(
3094 const std::list<std::unique_ptr<C2Work>> &workItems) {
3095 if (mApexBase) {
3096 // no-op
3097 return;
3098 } else if (mAidlBase) {
3099 holdIgbaBlocks(workItems);
3100 } else {
3101 // Output bufferqueue-based blocks' lifetime management
3102 mOutputBufferQueue->holdBufferQueueBlocks(workItems);
3103 }
3104 }
3105
queue(std::list<std::unique_ptr<C2Work>> * const items)3106 c2_status_t Codec2Client::Component::queue(
3107 std::list<std::unique_ptr<C2Work>>* const items) {
3108 if (mApexBase) {
3109 mApexHandler->queue(*items);
3110 return C2_OK;
3111 }
3112 if (mAidlBase) {
3113 c2_aidl::WorkBundle workBundle;
3114 {
3115 ScopedTrace trace(ATRACE_TAG, "CCodec::Codec2Client::ToAidl");
3116 if (!c2_aidl::utils::ToAidl(&workBundle, *items, mAidlBufferPoolSender.get())) {
3117 LOG(ERROR) << "queue -- bad input.";
3118 return C2_TRANSACTION_FAILED;
3119 }
3120 }
3121 ::ndk::ScopedAStatus transStatus = mAidlBase->queue(workBundle);
3122 return GetC2Status(transStatus, "queue");
3123 }
3124 c2_hidl::WorkBundle workBundle;
3125 if (!c2_hidl::utils::objcpy(&workBundle, *items, mHidlBufferPoolSender.get())) {
3126 LOG(ERROR) << "queue -- bad input.";
3127 return C2_TRANSACTION_FAILED;
3128 }
3129 Return<c2_hidl::Status> transStatus = mHidlBase1_0->queue(workBundle);
3130 if (!transStatus.isOk()) {
3131 LOG(ERROR) << "queue -- transaction failed.";
3132 return C2_TRANSACTION_FAILED;
3133 }
3134 c2_status_t status =
3135 static_cast<c2_status_t>(static_cast<c2_hidl::Status>(transStatus));
3136 if (status != C2_OK) {
3137 LOG(DEBUG) << "queue -- call failed: " << status << ".";
3138 }
3139 return status;
3140 }
3141
flush(C2Component::flush_mode_t mode,std::list<std::unique_ptr<C2Work>> * const flushedWork)3142 c2_status_t Codec2Client::Component::flush(
3143 C2Component::flush_mode_t mode,
3144 std::list<std::unique_ptr<C2Work>>* const flushedWork) {
3145 (void)mode; // Flush mode isn't supported in HIDL/AIDL yet.
3146 if (mApexBase) {
3147 if (__builtin_available(android 36, *)) {
3148 return (c2_status_t)ApexCodec_Component_flush(mApexBase);
3149 } else {
3150 return C2_OMITTED;
3151 }
3152 }
3153 c2_status_t status = C2_OK;
3154 if (mAidlBase) {
3155 c2_aidl::WorkBundle workBundle;
3156 ::ndk::ScopedAStatus transStatus = mAidlBase->flush(&workBundle);
3157 c2_status_t status = GetC2Status(transStatus, "flush");
3158 if (status != C2_OK) {
3159 return status;
3160 }
3161 if (!c2_aidl::utils::FromAidl(flushedWork, workBundle)) {
3162 LOG(DEBUG) << "flush -- flushedWork corrupted.";
3163 return C2_CORRUPTED;
3164 }
3165 } else {
3166 Return<void> transStatus = mHidlBase1_0->flush(
3167 [&status, flushedWork](
3168 c2_hidl::Status s, const c2_hidl::WorkBundle& wb) {
3169 status = static_cast<c2_status_t>(s);
3170 if (status != C2_OK) {
3171 LOG(DEBUG) << "flush -- call failed: " << status << ".";
3172 return;
3173 }
3174 if (!c2_hidl::utils::objcpy(flushedWork, wb)) {
3175 status = C2_CORRUPTED;
3176 } else {
3177 status = C2_OK;
3178 }
3179 });
3180 if (!transStatus.isOk()) {
3181 LOG(ERROR) << "flush -- transaction failed.";
3182 return C2_TRANSACTION_FAILED;
3183 }
3184 }
3185
3186 // Indices of flushed work items.
3187 std::vector<uint64_t> flushedIndices;
3188 for (const std::unique_ptr<C2Work> &work : *flushedWork) {
3189 if (work) {
3190 if (work->worklets.empty()
3191 || !work->worklets.back()
3192 || (work->worklets.back()->output.flags &
3193 C2FrameData::FLAG_INCOMPLETE) == 0) {
3194 // input is complete
3195 flushedIndices.emplace_back(
3196 work->input.ordinal.frameIndex.peeku());
3197 }
3198 }
3199 }
3200
3201 if (mAidlBase) {
3202 holdIgbaBlocks(*flushedWork);
3203 } else {
3204 // Output bufferqueue-based blocks' lifetime management
3205 mOutputBufferQueue->holdBufferQueueBlocks(*flushedWork);
3206 }
3207
3208 return status;
3209 }
3210
drain(C2Component::drain_mode_t mode)3211 c2_status_t Codec2Client::Component::drain(C2Component::drain_mode_t mode) {
3212 if (mApexBase) {
3213 return C2_OMITTED;
3214 }
3215 if (mAidlBase) {
3216 ::ndk::ScopedAStatus transStatus = mAidlBase->drain(
3217 mode == C2Component::DRAIN_COMPONENT_WITH_EOS);
3218 return GetC2Status(transStatus, "drain");
3219 }
3220 Return<c2_hidl::Status> transStatus = mHidlBase1_0->drain(
3221 mode == C2Component::DRAIN_COMPONENT_WITH_EOS);
3222 if (!transStatus.isOk()) {
3223 LOG(ERROR) << "drain -- transaction failed.";
3224 return C2_TRANSACTION_FAILED;
3225 }
3226 c2_status_t status =
3227 static_cast<c2_status_t>(static_cast<c2_hidl::Status>(transStatus));
3228 if (status != C2_OK) {
3229 LOG(DEBUG) << "drain -- call failed: " << status << ".";
3230 }
3231 return status;
3232 }
3233
start()3234 c2_status_t Codec2Client::Component::start() {
3235 if (mApexBase) {
3236 // no-op
3237 return C2_OK;
3238 }
3239 if (mAidlBase) {
3240 ::ndk::ScopedAStatus transStatus = mAidlBase->start();
3241 return GetC2Status(transStatus, "start");
3242 }
3243 Return<c2_hidl::Status> transStatus = mHidlBase1_0->start();
3244 if (!transStatus.isOk()) {
3245 LOG(ERROR) << "start -- transaction failed.";
3246 return C2_TRANSACTION_FAILED;
3247 }
3248 c2_status_t status =
3249 static_cast<c2_status_t>(static_cast<c2_hidl::Status>(transStatus));
3250 if (status != C2_OK) {
3251 LOG(DEBUG) << "start -- call failed: " << status << ".";
3252 }
3253 return status;
3254 }
3255
stop()3256 c2_status_t Codec2Client::Component::stop() {
3257 if (mAidlBase) {
3258 std::shared_ptr<AidlGraphicBufferAllocator> gba =
3259 mGraphicBufferAllocators->current();
3260 if (gba) {
3261 gba->onRequestStop();
3262 }
3263 ::ndk::ScopedAStatus transStatus = mAidlBase->stop();
3264 return GetC2Status(transStatus, "stop");
3265 }
3266 Return<c2_hidl::Status> transStatus = mHidlBase1_0->stop();
3267 if (!transStatus.isOk()) {
3268 LOG(ERROR) << "stop -- transaction failed.";
3269 return C2_TRANSACTION_FAILED;
3270 }
3271 c2_status_t status =
3272 static_cast<c2_status_t>(static_cast<c2_hidl::Status>(transStatus));
3273 if (status != C2_OK) {
3274 LOG(DEBUG) << "stop -- call failed: " << status << ".";
3275 }
3276 return status;
3277 }
3278
reset()3279 c2_status_t Codec2Client::Component::reset() {
3280 if (mApexBase) {
3281 if (__builtin_available(android 36, *)) {
3282 return (c2_status_t)ApexCodec_Component_reset(mApexBase);
3283 } else {
3284 return C2_OMITTED;
3285 }
3286 }
3287 if (mAidlBase) {
3288 ::ndk::ScopedAStatus transStatus = mAidlBase->reset();
3289 return GetC2Status(transStatus, "reset");
3290 }
3291 Return<c2_hidl::Status> transStatus = mHidlBase1_0->reset();
3292 if (!transStatus.isOk()) {
3293 LOG(ERROR) << "reset -- transaction failed.";
3294 return C2_TRANSACTION_FAILED;
3295 }
3296 c2_status_t status =
3297 static_cast<c2_status_t>(static_cast<c2_hidl::Status>(transStatus));
3298 if (status != C2_OK) {
3299 LOG(DEBUG) << "reset -- call failed: " << status << ".";
3300 }
3301 return status;
3302 }
3303
release()3304 c2_status_t Codec2Client::Component::release() {
3305 if (mApexBase) {
3306 if (__builtin_available(android 36, *)) {
3307 return (c2_status_t)ApexCodec_Component_reset(mApexBase);
3308 } else {
3309 return C2_OMITTED;
3310 }
3311 }
3312 if (mAidlBase) {
3313 std::shared_ptr<AidlGraphicBufferAllocator> gba =
3314 mGraphicBufferAllocators->current();
3315 if (gba) {
3316 gba->onRequestStop();
3317 }
3318 ::ndk::ScopedAStatus transStatus = mAidlBase->release();
3319 return GetC2Status(transStatus, "release");
3320 }
3321 Return<c2_hidl::Status> transStatus = mHidlBase1_0->release();
3322 if (!transStatus.isOk()) {
3323 LOG(ERROR) << "release -- transaction failed.";
3324 return C2_TRANSACTION_FAILED;
3325 }
3326 c2_status_t status =
3327 static_cast<c2_status_t>(static_cast<c2_hidl::Status>(transStatus));
3328 if (status != C2_OK) {
3329 LOG(DEBUG) << "release -- call failed: " << status << ".";
3330 }
3331 return status;
3332 }
3333
configureVideoTunnel(uint32_t avSyncHwId,native_handle_t ** sidebandHandle)3334 c2_status_t Codec2Client::Component::configureVideoTunnel(
3335 uint32_t avSyncHwId,
3336 native_handle_t** sidebandHandle) {
3337 *sidebandHandle = nullptr;
3338 if (mApexBase) {
3339 // tunneling is not supported in APEX
3340 return C2_OMITTED;
3341 }
3342 if (mAidlBase) {
3343 ::aidl::android::hardware::common::NativeHandle handle;
3344 ::ndk::ScopedAStatus transStatus = mAidlBase->configureVideoTunnel(avSyncHwId, &handle);
3345 c2_status_t status = GetC2Status(transStatus, "configureVideoTunnel");
3346 if (status != C2_OK) {
3347 return status;
3348 }
3349 if (isAidlNativeHandleEmpty(handle)) {
3350 LOG(DEBUG) << "configureVideoTunnel -- empty handle returned";
3351 } else {
3352 *sidebandHandle = dupFromAidl(handle);
3353 }
3354 return C2_OK;
3355 }
3356 if (!mHidlBase1_1) {
3357 return C2_OMITTED;
3358 }
3359 c2_status_t status{};
3360 Return<void> transStatus = mHidlBase1_1->configureVideoTunnel(avSyncHwId,
3361 [&status, sidebandHandle](
3362 c2_hidl::Status s, hardware::hidl_handle const& h) {
3363 status = static_cast<c2_status_t>(s);
3364 if (h.getNativeHandle()) {
3365 *sidebandHandle = native_handle_clone(h.getNativeHandle());
3366 }
3367 });
3368 if (!transStatus.isOk()) {
3369 LOG(ERROR) << "configureVideoTunnel -- transaction failed.";
3370 return C2_TRANSACTION_FAILED;
3371 }
3372 return status;
3373 }
3374
setOutputSurface(C2BlockPool::local_id_t blockPoolId,const sp<IGraphicBufferProducer> & surface,uint32_t generation,int maxDequeueCount)3375 c2_status_t Codec2Client::Component::setOutputSurface(
3376 C2BlockPool::local_id_t blockPoolId,
3377 const sp<IGraphicBufferProducer>& surface,
3378 uint32_t generation,
3379 int maxDequeueCount) {
3380 if (mAidlBase) {
3381 std::shared_ptr<AidlGraphicBufferAllocator> gba =
3382 mGraphicBufferAllocators->current();
3383 if (!gba) {
3384 LOG(ERROR) << "setOutputSurface for AIDL -- "
3385 "GraphicBufferAllocator was not created.";
3386 return C2_CORRUPTED;
3387 }
3388 // Note: Consumer usage is set ahead of the HAL allocator(gba) being set.
3389 // This is same as HIDL.
3390 uint64_t consumerUsage = configConsumerUsage(surface);
3391 bool ret = gba->configure(surface, generation, maxDequeueCount);
3392 ALOGD("setOutputSurface -- generation=%u consumer usage=%#llx",
3393 generation, (long long)consumerUsage);
3394 return ret ? C2_OK : C2_CORRUPTED;
3395 }
3396 uint64_t bqId = 0;
3397 sp<IGraphicBufferProducer> nullIgbp;
3398 sp<HGraphicBufferProducer2> nullHgbp;
3399
3400 sp<HGraphicBufferProducer2> igbp = surface ?
3401 surface->getHalInterface<HGraphicBufferProducer2>() : nullHgbp;
3402 if (surface && !igbp) {
3403 igbp = new B2HGraphicBufferProducer2(surface);
3404 }
3405
3406 std::scoped_lock lock(mOutputMutex);
3407 std::shared_ptr<SurfaceSyncObj> syncObj;
3408
3409 if (!surface) {
3410 mOutputBufferQueue->configure(nullIgbp, generation, 0, maxDequeueCount, nullptr);
3411 } else if (surface->getUniqueId(&bqId) != OK) {
3412 LOG(ERROR) << "setOutputSurface -- "
3413 "cannot obtain bufferqueue id.";
3414 bqId = 0;
3415 mOutputBufferQueue->configure(nullIgbp, generation, 0, maxDequeueCount, nullptr);
3416 } else {
3417 mOutputBufferQueue->configure(surface, generation, bqId, maxDequeueCount,
3418 mHidlBase1_2 ? &syncObj : nullptr);
3419 }
3420
3421 uint64_t consumerUsage = configConsumerUsage(surface);
3422 ALOGD("setOutputSurface -- generation=%u consumer usage=%#llx%s",
3423 generation, (long long)consumerUsage, syncObj ? " sync" : "");
3424
3425 Return<c2_hidl::Status> transStatus = syncObj ?
3426 mHidlBase1_2->setOutputSurfaceWithSyncObj(
3427 static_cast<uint64_t>(blockPoolId),
3428 bqId == 0 ? nullHgbp : igbp, *syncObj) :
3429 mHidlBase1_0->setOutputSurface(
3430 static_cast<uint64_t>(blockPoolId),
3431 bqId == 0 ? nullHgbp : igbp);
3432
3433 mOutputBufferQueue->expireOldWaiters();
3434
3435 if (!transStatus.isOk()) {
3436 LOG(ERROR) << "setOutputSurface -- transaction failed.";
3437 return C2_TRANSACTION_FAILED;
3438 }
3439 c2_status_t status =
3440 static_cast<c2_status_t>(static_cast<c2_hidl::Status>(transStatus));
3441 if (status != C2_OK) {
3442 LOG(DEBUG) << "setOutputSurface -- call failed: " << status << ".";
3443 }
3444 ALOGD("Surface configure completed");
3445 return status;
3446 }
3447
queueToOutputSurface(const C2ConstGraphicBlock & block,const QueueBufferInput & input,QueueBufferOutput * output)3448 status_t Codec2Client::Component::queueToOutputSurface(
3449 const C2ConstGraphicBlock& block,
3450 const QueueBufferInput& input,
3451 QueueBufferOutput* output) {
3452 ScopedTrace trace(ATRACE_TAG,"CCodec::Codec2Client::Component::queueToOutputSurface");
3453 if (mAidlBase) {
3454 std::shared_ptr<AidlGraphicBufferAllocator> gba =
3455 mGraphicBufferAllocators->current();
3456 if (gba) {
3457 return gba->displayBuffer(block, input, output);
3458 } else {
3459 return C2_NOT_FOUND;
3460 }
3461 }
3462 return mOutputBufferQueue->outputBuffer(block, input, output);
3463 }
3464
configConsumerUsage(const sp<IGraphicBufferProducer> & surface)3465 uint64_t Codec2Client::Component::configConsumerUsage(
3466 const sp<IGraphicBufferProducer>& surface) {
3467 // set consumer bits
3468 // TODO: should this get incorporated into setOutputSurface method so that consumer bits
3469 // can be set atomically?
3470 uint64_t consumerUsage = kDefaultConsumerUsage;
3471 {
3472 if (surface) {
3473 uint64_t usage = 0;
3474 status_t err = surface->getConsumerUsage(&usage);
3475 if (err != NO_ERROR) {
3476 ALOGD("setOutputSurface -- failed to get consumer usage bits (%d/%s). ignoring",
3477 err, asString(err));
3478 } else {
3479 // Note: we are adding the default usage because components must support
3480 // producing output frames that can be displayed an all output surfaces.
3481
3482 // TODO: do not set usage for tunneled scenario. It is unclear if consumer usage
3483 // is meaningful in a tunneled scenario; on one hand output buffers exist, but
3484 // they do not exist inside of C2 scope. Any buffer usage shall be communicated
3485 // through the sideband channel.
3486
3487 consumerUsage = usage | kDefaultConsumerUsage;
3488 }
3489 }
3490
3491 C2StreamUsageTuning::output outputUsage{
3492 0u, C2AndroidMemoryUsage::FromGrallocUsage(consumerUsage).expected};
3493 std::vector<std::unique_ptr<C2SettingResult>> failures;
3494 c2_status_t err = config({&outputUsage}, C2_MAY_BLOCK, &failures);
3495 if (err != C2_OK) {
3496 ALOGD("setOutputSurface -- failed to set consumer usage (%d/%s)",
3497 err, asString(err));
3498 }
3499 }
3500 return consumerUsage;
3501 }
3502
pollForRenderedFrames(FrameEventHistoryDelta * delta)3503 void Codec2Client::Component::pollForRenderedFrames(FrameEventHistoryDelta* delta) {
3504 if (mAidlBase) {
3505 std::shared_ptr<AidlGraphicBufferAllocator> gba =
3506 mGraphicBufferAllocators->current();
3507 if (gba) {
3508 gba->pollForRenderedFrames(delta);
3509 }
3510 return;
3511 }
3512 mOutputBufferQueue->pollForRenderedFrames(delta);
3513 }
3514
setOutputSurfaceMaxDequeueCount(int maxDequeueCount)3515 void Codec2Client::Component::setOutputSurfaceMaxDequeueCount(
3516 int maxDequeueCount) {
3517 if (mAidlBase) {
3518 std::shared_ptr<AidlGraphicBufferAllocator> gba =
3519 mGraphicBufferAllocators->current();
3520 if (gba) {
3521 gba->updateMaxDequeueBufferCount(maxDequeueCount);
3522 }
3523 return;
3524 }
3525 mOutputBufferQueue->updateMaxDequeueBufferCount(maxDequeueCount);
3526 }
3527
stopUsingOutputSurface(C2BlockPool::local_id_t blockPoolId)3528 void Codec2Client::Component::stopUsingOutputSurface(
3529 C2BlockPool::local_id_t blockPoolId) {
3530 if (mAidlBase) {
3531 std::shared_ptr<AidlGraphicBufferAllocator> gba =
3532 mGraphicBufferAllocators->current();
3533 if (gba) {
3534 gba->reset();
3535 }
3536 return;
3537 }
3538 std::scoped_lock lock(mOutputMutex);
3539 mOutputBufferQueue->stop();
3540 Return<c2_hidl::Status> transStatus = mHidlBase1_0->setOutputSurface(
3541 static_cast<uint64_t>(blockPoolId), nullptr);
3542 if (!transStatus.isOk()) {
3543 LOG(ERROR) << "setOutputSurface(stopUsingOutputSurface) -- transaction failed.";
3544 } else {
3545 c2_status_t status =
3546 static_cast<c2_status_t>(static_cast<c2_hidl::Status>(transStatus));
3547 if (status != C2_OK) {
3548 LOG(DEBUG) << "setOutputSurface(stopUsingOutputSurface) -- call failed: "
3549 << status << ".";
3550 }
3551 }
3552 mOutputBufferQueue->expireOldWaiters();
3553 }
3554
onBufferReleasedFromOutputSurface(uint32_t generation)3555 void Codec2Client::Component::onBufferReleasedFromOutputSurface(
3556 uint32_t generation) {
3557 if (mAidlBase) {
3558 std::shared_ptr<AidlGraphicBufferAllocator> gba =
3559 mGraphicBufferAllocators->current();
3560 if (gba) {
3561 gba->onBufferReleased(generation);
3562 }
3563 return;
3564 }
3565 mOutputBufferQueue->onBufferReleased(generation);
3566 }
3567
onBufferAttachedToOutputSurface(uint32_t generation)3568 void Codec2Client::Component::onBufferAttachedToOutputSurface(
3569 uint32_t generation) {
3570 if (mAidlBase) {
3571 std::shared_ptr<AidlGraphicBufferAllocator> gba =
3572 mGraphicBufferAllocators->current();
3573 if (gba) {
3574 gba->onBufferAttached(generation);
3575 }
3576 return;
3577 }
3578 mOutputBufferQueue->onBufferAttached(generation);
3579 }
3580
holdIgbaBlocks(const std::list<std::unique_ptr<C2Work>> & workList)3581 void Codec2Client::Component::holdIgbaBlocks(
3582 const std::list<std::unique_ptr<C2Work>>& workList) {
3583 if (!mAidlBase) {
3584 return;
3585 }
3586 std::shared_ptr<AidlGraphicBufferAllocator> gba =
3587 mGraphicBufferAllocators->current();
3588 if (!gba) {
3589 return;
3590 }
3591 std::shared_ptr<c2_aidl::IGraphicBufferAllocator> igba =
3592 c2_aidl::IGraphicBufferAllocator::fromBinder(gba->asBinder());
3593 for (const std::unique_ptr<C2Work>& work : workList) {
3594 if (!work) [[unlikely]] {
3595 continue;
3596 }
3597 for (const std::unique_ptr<C2Worklet>& worklet : work->worklets) {
3598 if (!worklet) {
3599 continue;
3600 }
3601 for (const std::shared_ptr<C2Buffer>& buffer : worklet->output.buffers) {
3602 if (buffer) {
3603 for (const C2ConstGraphicBlock& block : buffer->data().graphicBlocks()) {
3604 std::shared_ptr<_C2BlockPoolData> poolData =
3605 _C2BlockFactory::GetGraphicBlockPoolData(block);
3606 _C2BlockFactory::RegisterIgba(poolData, igba);
3607 }
3608 }
3609 }
3610 }
3611 }
3612 }
3613
connectToInputSurface(const std::shared_ptr<InputSurface> & inputSurface,std::shared_ptr<InputSurfaceConnection> * connection)3614 c2_status_t Codec2Client::Component::connectToInputSurface(
3615 const std::shared_ptr<InputSurface>& inputSurface,
3616 std::shared_ptr<InputSurfaceConnection>* connection) {
3617 if (mApexBase) {
3618 // FIXME
3619 return C2_OMITTED;
3620 }
3621 if (mAidlBase) {
3622 // FIXME
3623 return C2_OMITTED;
3624 }
3625 c2_status_t status;
3626 Return<void> transStatus = mHidlBase1_0->connectToInputSurface(
3627 inputSurface->mBase,
3628 [&status, connection](
3629 c2_hidl::Status s, const sp<c2_hidl::IInputSurfaceConnection>& c) {
3630 status = static_cast<c2_status_t>(s);
3631 if (status != C2_OK) {
3632 LOG(DEBUG) << "connectToInputSurface -- call failed: "
3633 << status << ".";
3634 return;
3635 }
3636 *connection = std::make_shared<InputSurfaceConnection>(c);
3637 });
3638 if (!transStatus.isOk()) {
3639 LOG(ERROR) << "connectToInputSurface -- transaction failed";
3640 return C2_TRANSACTION_FAILED;
3641 }
3642 return status;
3643 }
3644
connectToOmxInputSurface(const sp<HGraphicBufferProducer1> & producer,const sp<HGraphicBufferSource> & source,std::shared_ptr<InputSurfaceConnection> * connection)3645 c2_status_t Codec2Client::Component::connectToOmxInputSurface(
3646 const sp<HGraphicBufferProducer1>& producer,
3647 const sp<HGraphicBufferSource>& source,
3648 std::shared_ptr<InputSurfaceConnection>* connection) {
3649 if (mApexBase) {
3650 LOG(WARNING) << "Connecting to OMX input surface is not supported for AIDL C2 HAL";
3651 return C2_OMITTED;
3652 }
3653 if (mAidlBase) {
3654 LOG(WARNING) << "Connecting to OMX input surface is not supported for AIDL C2 HAL";
3655 return C2_OMITTED;
3656 }
3657 c2_status_t status;
3658 Return<void> transStatus = mHidlBase1_0->connectToOmxInputSurface(
3659 producer, source,
3660 [&status, connection](
3661 c2_hidl::Status s, const sp<c2_hidl::IInputSurfaceConnection>& c) {
3662 status = static_cast<c2_status_t>(s);
3663 if (status != C2_OK) {
3664 LOG(DEBUG) << "connectToOmxInputSurface -- call failed: "
3665 << status << ".";
3666 return;
3667 }
3668 *connection = std::make_shared<InputSurfaceConnection>(c);
3669 });
3670 if (!transStatus.isOk()) {
3671 LOG(ERROR) << "connectToOmxInputSurface -- transaction failed.";
3672 return C2_TRANSACTION_FAILED;
3673 }
3674 return status;
3675 }
3676
disconnectFromInputSurface()3677 c2_status_t Codec2Client::Component::disconnectFromInputSurface() {
3678 if (mApexBase) {
3679 // FIXME
3680 return C2_OMITTED;
3681 }
3682 if (mAidlBase) {
3683 // FIXME
3684 return C2_OMITTED;
3685 }
3686 Return<c2_hidl::Status> transStatus = mHidlBase1_0->disconnectFromInputSurface();
3687 if (!transStatus.isOk()) {
3688 LOG(ERROR) << "disconnectToInputSurface -- transaction failed.";
3689 return C2_TRANSACTION_FAILED;
3690 }
3691 c2_status_t status =
3692 static_cast<c2_status_t>(static_cast<c2_hidl::Status>(transStatus));
3693 if (status != C2_OK) {
3694 LOG(DEBUG) << "disconnectFromInputSurface -- call failed: "
3695 << status << ".";
3696 }
3697 return status;
3698 }
3699
GetAidlDeathManager()3700 Codec2Client::Component::AidlDeathManager *Codec2Client::Component::GetAidlDeathManager() {
3701 // This object never gets destructed
3702 static AidlDeathManager *sManager = new AidlDeathManager();
3703 return sManager;
3704 }
3705
initApexHandler(const std::shared_ptr<Listener> & listener,const std::shared_ptr<Component> & comp)3706 c2_status_t Codec2Client::Component::initApexHandler(
3707 const std::shared_ptr<Listener> &listener,
3708 const std::shared_ptr<Component> &comp) {
3709 if (!mApexBase) {
3710 return C2_BAD_STATE;
3711 }
3712 mApexHandler = std::make_unique<ApexHandler>(mApexBase, listener, comp);
3713 return C2_OK;
3714 }
3715
setDeathListener(const std::shared_ptr<Component> & component,const std::shared_ptr<Listener> & listener)3716 c2_status_t Codec2Client::Component::setDeathListener(
3717 const std::shared_ptr<Component>& component,
3718 const std::shared_ptr<Listener>& listener) {
3719
3720 struct HidlDeathRecipient : public hardware::hidl_death_recipient {
3721 std::weak_ptr<Component> component;
3722 std::weak_ptr<Listener> base;
3723
3724 virtual void serviceDied(
3725 uint64_t /* cookie */,
3726 const wp<::android::hidl::base::V1_0::IBase>& /* who */
3727 ) override {
3728 if (std::shared_ptr<Codec2Client::Listener> listener = base.lock()) {
3729 listener->onDeath(component);
3730 } else {
3731 LOG(DEBUG) << "onDeath -- listener died.";
3732 }
3733 }
3734 };
3735
3736 if (component->mAidlBase) {
3737 size_t seq;
3738 if (GetAidlDeathManager()->linkToDeath(component, listener, &seq)) {
3739 component->mAidlDeathSeq = seq;
3740 }
3741 return C2_OK;
3742 }
3743
3744 sp<HidlDeathRecipient> deathRecipient = new HidlDeathRecipient();
3745 deathRecipient->base = listener;
3746 deathRecipient->component = component;
3747
3748 component->mDeathRecipient = deathRecipient;
3749 Return<bool> transResult = component->mHidlBase1_0->linkToDeath(
3750 component->mDeathRecipient, 0);
3751 if (!transResult.isOk()) {
3752 LOG(ERROR) << "setDeathListener -- linkToDeath() transaction failed.";
3753 return C2_TRANSACTION_FAILED;
3754 }
3755 if (!static_cast<bool>(transResult)) {
3756 LOG(DEBUG) << "setDeathListener -- linkToDeath() call failed.";
3757 return C2_CORRUPTED;
3758 }
3759 return C2_OK;
3760 }
3761
3762 // Codec2Client::InputSurface
InputSurface(const sp<c2_hidl::IInputSurface> & base)3763 Codec2Client::InputSurface::InputSurface(const sp<c2_hidl::IInputSurface>& base)
3764 : Configurable{
3765 [base]() -> sp<c2_hidl::IConfigurable> {
3766 Return<sp<c2_hidl::IConfigurable>> transResult =
3767 base->getConfigurable();
3768 return transResult.isOk() ?
3769 static_cast<sp<c2_hidl::IConfigurable>>(transResult) :
3770 nullptr;
3771 }()
3772 },
3773 mBase{base},
3774 mGraphicBufferProducer{new
__anon926bcd9b3102() 3775 H2BGraphicBufferProducer2([base]() -> sp<HGraphicBufferProducer2> {
3776 Return<sp<HGraphicBufferProducer2>> transResult =
3777 base->getGraphicBufferProducer();
3778 return transResult.isOk() ?
3779 static_cast<sp<HGraphicBufferProducer2>>(transResult) :
3780 nullptr;
3781 }())} {
3782 }
3783
3784 sp<IGraphicBufferProducer>
getGraphicBufferProducer() const3785 Codec2Client::InputSurface::getGraphicBufferProducer() const {
3786 return mGraphicBufferProducer;
3787 }
3788
getHalInterface() const3789 sp<c2_hidl::IInputSurface> Codec2Client::InputSurface::getHalInterface() const {
3790 return mBase;
3791 }
3792
3793 // Codec2Client::InputSurfaceConnection
InputSurfaceConnection(const sp<c2_hidl::IInputSurfaceConnection> & base)3794 Codec2Client::InputSurfaceConnection::InputSurfaceConnection(
3795 const sp<c2_hidl::IInputSurfaceConnection>& base)
3796 : Configurable{
3797 [base]() -> sp<c2_hidl::IConfigurable> {
3798 Return<sp<c2_hidl::IConfigurable>> transResult =
3799 base->getConfigurable();
3800 return transResult.isOk() ?
3801 static_cast<sp<c2_hidl::IConfigurable>>(transResult) :
3802 nullptr;
3803 }()
3804 },
3805 mBase{base} {
3806 }
3807
disconnect()3808 c2_status_t Codec2Client::InputSurfaceConnection::disconnect() {
3809 Return<c2_hidl::Status> transResult = mBase->disconnect();
3810 return static_cast<c2_status_t>(static_cast<c2_hidl::Status>(transResult));
3811 }
3812
3813 } // namespace android
3814