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