• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 &params,
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*> &params,
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(&paramPointers, 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*> &params,
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, &params, 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*> &params,
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(&paramPointers, 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*> &params,
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*> &params,
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(&paramPointers, 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*> &params,
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, &paramDescs);
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*> &params,
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