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