xref: /aosp_15_r20/frameworks/av/media/codec2/hal/client/ApexCodecsLazy.cpp (revision ec779b8e0859a360c3d303172224686826e6e0e1)
1 /*
2  * Copyright (C) 2024 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 "ApexCodecsLazy"
19 #include <log/log.h>
20 
21 #include <mutex>
22 
23 #include <dlfcn.h>
24 
25 #include <android-base/no_destructor.h>
26 #include <apex/ApexCodecs.h>
27 #include <utils/RWLock.h>
28 
29 using android::RWLock;
30 
31 namespace {
32 
33 // This file provides a lazy interface to libapexcodecs.so to address early boot dependencies.
34 
35 // Method pointers to libapexcodecs methods are held in an array which simplifies checking
36 // all pointers are initialized.
37 enum MethodIndex {
38     k_ApexCodec_Component_create,
39     k_ApexCodec_Component_destroy,
40     k_ApexCodec_Component_flush,
41     k_ApexCodec_Component_getConfigurable,
42     k_ApexCodec_Component_process,
43     k_ApexCodec_Component_start,
44     k_ApexCodec_Component_reset,
45     k_ApexCodec_Configurable_config,
46     k_ApexCodec_Configurable_query,
47     k_ApexCodec_Configurable_querySupportedParams,
48     k_ApexCodec_Configurable_querySupportedValues,
49     k_ApexCodec_GetComponentStore,
50     k_ApexCodec_ParamDescriptors_getDescriptor,
51     k_ApexCodec_ParamDescriptors_getIndices,
52     k_ApexCodec_ParamDescriptors_release,
53     k_ApexCodec_SettingResults_getResultAtIndex,
54     k_ApexCodec_SettingResults_release,
55     k_ApexCodec_SupportedValues_getTypeAndValues,
56     k_ApexCodec_SupportedValues_release,
57     k_ApexCodec_Traits_get,
58 
59     // Marker for count of methods
60     k_MethodCount
61 };
62 
63 class ApexCodecsLazyLoader {
64 public:
65     ApexCodecsLazyLoader() = default;
66 
Get()67     static ApexCodecsLazyLoader &Get() {
68         static ::android::base::NoDestructor<ApexCodecsLazyLoader> sLoader;
69         return *sLoader;
70     }
71 
getMethodAt(enum MethodIndex index)72     void *getMethodAt(enum MethodIndex index) {
73         RWLock::AutoRLock l(mLock);
74         if (mInit) {
75             return mMethods[index];
76         } else {
77             mLock.unlock();
78             if (!init()) {
79                 return nullptr;
80             }
81             mLock.readLock();
82             return mMethods[index];
83         }
84     }
85 
86 private:
LoadLibapexcodecs(int dlopen_flags)87     static void* LoadLibapexcodecs(int dlopen_flags) {
88         return dlopen("libapexcodecs.so", dlopen_flags);
89     }
90 
91     // Initialization and symbol binding.
bindSymbol_l(void * handle,const char * name,enum MethodIndex index)92     void bindSymbol_l(void* handle, const char* name, enum MethodIndex index) {
93         void* symbol = dlsym(handle, name);
94         ALOGI_IF(symbol == nullptr, "Failed to find symbol '%s' in libapexcodecs.so: %s",
95                  name, dlerror());
96         mMethods[index] = symbol;
97     }
98 
init()99     bool init() {
100         {
101             RWLock::AutoRLock l(mLock);
102             if (mInit) {
103                 return true;
104             }
105         }
106         void* handle = LoadLibapexcodecs(RTLD_NOW);
107         if (handle == nullptr) {
108             ALOGI("Failed to load libapexcodecs.so: %s", dlerror());
109             return false;
110         }
111 
112         RWLock::AutoWLock l(mLock);
113 #undef BIND_SYMBOL
114 #define BIND_SYMBOL(name) bindSymbol_l(handle, #name, k_##name);
115         BIND_SYMBOL(ApexCodec_Component_create);
116         BIND_SYMBOL(ApexCodec_Component_destroy);
117         BIND_SYMBOL(ApexCodec_Component_flush);
118         BIND_SYMBOL(ApexCodec_Component_getConfigurable);
119         BIND_SYMBOL(ApexCodec_Component_process);
120         BIND_SYMBOL(ApexCodec_Component_start);
121         BIND_SYMBOL(ApexCodec_Component_reset);
122         BIND_SYMBOL(ApexCodec_Configurable_config);
123         BIND_SYMBOL(ApexCodec_Configurable_query);
124         BIND_SYMBOL(ApexCodec_Configurable_querySupportedParams);
125         BIND_SYMBOL(ApexCodec_Configurable_querySupportedValues);
126         BIND_SYMBOL(ApexCodec_GetComponentStore);
127         BIND_SYMBOL(ApexCodec_ParamDescriptors_getDescriptor);
128         BIND_SYMBOL(ApexCodec_ParamDescriptors_getIndices);
129         BIND_SYMBOL(ApexCodec_ParamDescriptors_release);
130         BIND_SYMBOL(ApexCodec_SettingResults_getResultAtIndex);
131         BIND_SYMBOL(ApexCodec_SettingResults_release);
132         BIND_SYMBOL(ApexCodec_SupportedValues_getTypeAndValues);
133         BIND_SYMBOL(ApexCodec_SupportedValues_release);
134         BIND_SYMBOL(ApexCodec_Traits_get);
135 #undef BIND_SYMBOL
136 
137         // Check every symbol is bound.
138         for (int i = 0; i < k_MethodCount; ++i) {
139             if (mMethods[i] == nullptr) {
140                 ALOGI("Uninitialized method in libapexcodecs_lazy at index: %d", i);
141                 return false;
142             }
143         }
144         mInit = true;
145         return true;
146     }
147 
148     RWLock mLock;
149     // Table of methods pointers in libapexcodecs APIs.
150     void* mMethods[k_MethodCount];
151     bool mInit{false};
152 };
153 
154 }  // anonymous namespace
155 
156 #define INVOKE_METHOD(name, returnIfNull, args...)                          \
157     do {                                                                    \
158         void* method = ApexCodecsLazyLoader::Get().getMethodAt(k_##name);   \
159         if (!method) return (returnIfNull);                                 \
160         return reinterpret_cast<decltype(&name)>(method)(args);             \
161     } while (0)
162 
163 //
164 // Forwarding for methods in ApexCodecs.h.
165 //
166 
ApexCodec_GetComponentStore()167 ApexCodec_ComponentStore *ApexCodec_GetComponentStore() {
168     INVOKE_METHOD(ApexCodec_GetComponentStore, nullptr);
169 }
170 
ApexCodec_Traits_get(ApexCodec_ComponentStore * store,size_t index)171 ApexCodec_ComponentTraits *ApexCodec_Traits_get(
172         ApexCodec_ComponentStore *store, size_t index) {
173     INVOKE_METHOD(ApexCodec_Traits_get, nullptr, store, index);
174 }
175 
ApexCodec_Component_create(ApexCodec_ComponentStore * store,const char * name,ApexCodec_Component ** comp)176 ApexCodec_Status ApexCodec_Component_create(
177         ApexCodec_ComponentStore *store, const char *name, ApexCodec_Component **comp) {
178     INVOKE_METHOD(ApexCodec_Component_create, APEXCODEC_STATUS_OMITTED, store, name, comp);
179 }
180 
ApexCodec_Component_destroy(ApexCodec_Component * comp)181 void ApexCodec_Component_destroy(ApexCodec_Component *comp) {
182     INVOKE_METHOD(ApexCodec_Component_destroy, void(), comp);
183 }
184 
ApexCodec_Component_start(ApexCodec_Component * comp)185 ApexCodec_Status ApexCodec_Component_start(ApexCodec_Component *comp) {
186     INVOKE_METHOD(ApexCodec_Component_start, APEXCODEC_STATUS_OMITTED, comp);
187 }
188 
ApexCodec_Component_flush(ApexCodec_Component * comp)189 ApexCodec_Status ApexCodec_Component_flush(ApexCodec_Component *comp) {
190     INVOKE_METHOD(ApexCodec_Component_flush, APEXCODEC_STATUS_OMITTED, comp);
191 }
192 
ApexCodec_Component_reset(ApexCodec_Component * comp)193 ApexCodec_Status ApexCodec_Component_reset(ApexCodec_Component *comp) {
194     INVOKE_METHOD(ApexCodec_Component_reset, APEXCODEC_STATUS_OMITTED, comp);
195 }
196 
ApexCodec_Component_getConfigurable(ApexCodec_Component * comp)197 ApexCodec_Configurable *ApexCodec_Component_getConfigurable(
198         ApexCodec_Component *comp) {
199     INVOKE_METHOD(ApexCodec_Component_getConfigurable, nullptr, comp);
200 }
201 
ApexCodec_SupportedValues_getTypeAndValues(ApexCodec_SupportedValues * supportedValues,ApexCodec_SupportedValuesType * type,ApexCodec_SupportedValuesNumberType * numberType,ApexCodec_Value ** values,uint32_t * numValues)202 ApexCodec_Status ApexCodec_SupportedValues_getTypeAndValues(
203         ApexCodec_SupportedValues *supportedValues,
204         ApexCodec_SupportedValuesType *type,
205         ApexCodec_SupportedValuesNumberType *numberType,
206         ApexCodec_Value **values,
207         uint32_t *numValues) {
208     INVOKE_METHOD(ApexCodec_SupportedValues_getTypeAndValues, APEXCODEC_STATUS_OMITTED,
209                   supportedValues, type, numberType, values, numValues);
210 }
211 
ApexCodec_SupportedValues_release(ApexCodec_SupportedValues * values)212 void ApexCodec_SupportedValues_release(ApexCodec_SupportedValues *values) {
213     INVOKE_METHOD(ApexCodec_SupportedValues_release, void(), values);
214 }
215 
ApexCodec_SettingResults_getResultAtIndex(ApexCodec_SettingResults * results,size_t index,ApexCodec_SettingResultFailure * failure,ApexCodec_ParamFieldValues * field,ApexCodec_ParamFieldValues ** conflicts,size_t * numConflicts)216 ApexCodec_Status ApexCodec_SettingResults_getResultAtIndex(
217         ApexCodec_SettingResults *results,
218         size_t index,
219         ApexCodec_SettingResultFailure *failure,
220         ApexCodec_ParamFieldValues *field,
221         ApexCodec_ParamFieldValues **conflicts,
222         size_t *numConflicts) {
223     INVOKE_METHOD(ApexCodec_SettingResults_getResultAtIndex, APEXCODEC_STATUS_OMITTED,
224                   results, index, failure, field, conflicts, numConflicts);
225 }
226 
ApexCodec_SettingResults_release(ApexCodec_SettingResults * results)227 void ApexCodec_SettingResults_release(ApexCodec_SettingResults *results) {
228     INVOKE_METHOD(ApexCodec_SettingResults_release, void(), results);
229 }
230 
ApexCodec_Component_process(ApexCodec_Component * comp,const ApexCodec_Buffer * input,ApexCodec_Buffer * output,size_t * consumed,size_t * produced)231 ApexCodec_Status ApexCodec_Component_process(
232         ApexCodec_Component *comp,
233         const ApexCodec_Buffer *input,
234         ApexCodec_Buffer *output,
235         size_t *consumed,
236         size_t *produced) {
237     INVOKE_METHOD(ApexCodec_Component_process, APEXCODEC_STATUS_OMITTED,
238                   comp, input, output, consumed, produced);
239 }
240 
ApexCodec_Configurable_config(ApexCodec_Configurable * comp,ApexCodec_LinearBuffer * config,ApexCodec_SettingResults ** results)241 ApexCodec_Status ApexCodec_Configurable_config(
242         ApexCodec_Configurable *comp,
243         ApexCodec_LinearBuffer *config,
244         ApexCodec_SettingResults **results) {
245     INVOKE_METHOD(ApexCodec_Configurable_config, APEXCODEC_STATUS_OMITTED, comp, config, results);
246 }
247 
ApexCodec_Configurable_query(ApexCodec_Configurable * comp,uint32_t indices[],size_t numIndices,ApexCodec_LinearBuffer * config,size_t * writtenOrRequested)248 ApexCodec_Status ApexCodec_Configurable_query(
249         ApexCodec_Configurable *comp,
250         uint32_t indices[],
251         size_t numIndices,
252         ApexCodec_LinearBuffer *config,
253         size_t *writtenOrRequested) {
254     INVOKE_METHOD(ApexCodec_Configurable_query, APEXCODEC_STATUS_OMITTED,
255                   comp, indices, numIndices, config, writtenOrRequested);
256 }
257 
ApexCodec_ParamDescriptors_getIndices(ApexCodec_ParamDescriptors * descriptors,uint32_t ** indices,size_t * numIndices)258 ApexCodec_Status ApexCodec_ParamDescriptors_getIndices(
259         ApexCodec_ParamDescriptors *descriptors,
260         uint32_t **indices,
261         size_t *numIndices) {
262     INVOKE_METHOD(ApexCodec_ParamDescriptors_getIndices, APEXCODEC_STATUS_OMITTED,
263                   descriptors, indices, numIndices);
264 }
265 
ApexCodec_ParamDescriptors_getDescriptor(ApexCodec_ParamDescriptors * descriptors,uint32_t index,ApexCodec_ParamAttribute * attr,const char ** name,uint32_t ** dependencies,size_t * numDependencies)266 ApexCodec_Status ApexCodec_ParamDescriptors_getDescriptor(
267         ApexCodec_ParamDescriptors *descriptors,
268         uint32_t index,
269         ApexCodec_ParamAttribute *attr,
270         const char **name,
271         uint32_t **dependencies,
272         size_t *numDependencies) {
273     INVOKE_METHOD(ApexCodec_ParamDescriptors_getDescriptor, APEXCODEC_STATUS_OMITTED,
274                   descriptors, index, attr, name, dependencies, numDependencies);
275 }
276 
ApexCodec_ParamDescriptors_release(ApexCodec_ParamDescriptors * descriptors)277 ApexCodec_Status ApexCodec_ParamDescriptors_release(
278         ApexCodec_ParamDescriptors *descriptors) {
279     INVOKE_METHOD(ApexCodec_ParamDescriptors_release, APEXCODEC_STATUS_OMITTED, descriptors);
280 }
281 
ApexCodec_Configurable_querySupportedParams(ApexCodec_Configurable * comp,ApexCodec_ParamDescriptors ** descriptors)282 ApexCodec_Status ApexCodec_Configurable_querySupportedParams(
283         ApexCodec_Configurable *comp,
284         ApexCodec_ParamDescriptors **descriptors) {
285     INVOKE_METHOD(ApexCodec_Configurable_querySupportedParams, APEXCODEC_STATUS_OMITTED,
286                   comp, descriptors);
287 }
288 
ApexCodec_Configurable_querySupportedValues(ApexCodec_Configurable * comp,ApexCodec_SupportedValuesQuery * queries,size_t numQueries)289 ApexCodec_Status ApexCodec_Configurable_querySupportedValues(
290         ApexCodec_Configurable *comp,
291         ApexCodec_SupportedValuesQuery *queries,
292         size_t numQueries) {
293     INVOKE_METHOD(ApexCodec_Configurable_querySupportedValues, APEXCODEC_STATUS_OMITTED,
294                   comp, queries, numQueries);
295 }
296