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 libcom.android.media.swcodec.apexcodecs.so
34 // to address early boot dependencies.
35
36 // Method pointers to libcom.android.media.swcodec.apexcodecs methods are held in an array
37 // which simplifies checking all pointers are initialized.
38 enum MethodIndex {
39 k_ApexCodec_Buffer_clear,
40 k_ApexCodec_Buffer_create,
41 k_ApexCodec_Buffer_destroy,
42 k_ApexCodec_Buffer_getBufferInfo,
43 k_ApexCodec_Buffer_getConfigUpdates,
44 k_ApexCodec_Buffer_getGraphicBuffer,
45 k_ApexCodec_Buffer_getLinearBuffer,
46 k_ApexCodec_Buffer_getType,
47 k_ApexCodec_Buffer_setBufferInfo,
48 k_ApexCodec_Buffer_setConfigUpdates,
49 k_ApexCodec_Buffer_setGraphicBuffer,
50 k_ApexCodec_Buffer_setLinearBuffer,
51 k_ApexCodec_Component_create,
52 k_ApexCodec_Component_destroy,
53 k_ApexCodec_Component_flush,
54 k_ApexCodec_Component_getConfigurable,
55 k_ApexCodec_Component_process,
56 k_ApexCodec_Component_reset,
57 k_ApexCodec_Component_start,
58 k_ApexCodec_Configurable_config,
59 k_ApexCodec_Configurable_query,
60 k_ApexCodec_Configurable_querySupportedParams,
61 k_ApexCodec_Configurable_querySupportedValues,
62 k_ApexCodec_GetComponentStore,
63 k_ApexCodec_ParamDescriptors_destroy,
64 k_ApexCodec_ParamDescriptors_getDescriptor,
65 k_ApexCodec_ParamDescriptors_getIndices,
66 k_ApexCodec_SettingResults_destroy,
67 k_ApexCodec_SettingResults_getResultAtIndex,
68 k_ApexCodec_SupportedValues_destroy,
69 k_ApexCodec_SupportedValues_getTypeAndValues,
70 k_ApexCodec_Traits_get,
71
72 // Marker for count of methods
73 k_MethodCount
74 };
75
76 class ApexCodecsLazyLoader {
77 public:
78 ApexCodecsLazyLoader() = default;
79
Get()80 static ApexCodecsLazyLoader &Get() {
81 static ::android::base::NoDestructor<ApexCodecsLazyLoader> sLoader;
82 return *sLoader;
83 }
84
getMethodAt(enum MethodIndex index)85 void *getMethodAt(enum MethodIndex index) {
86 RWLock::AutoRLock l(mLock);
87 if (mInit) {
88 return mMethods[index];
89 } else {
90 mLock.unlock();
91 if (!init()) {
92 return nullptr;
93 }
94 mLock.readLock();
95 return mMethods[index];
96 }
97 }
98
99 private:
LoadApexCodecs(int dlopen_flags)100 static void* LoadApexCodecs(int dlopen_flags) {
101 return dlopen("libcom.android.media.swcodec.apexcodecs.so", dlopen_flags);
102 }
103
104 // Initialization and symbol binding.
bindSymbol_l(void * handle,const char * name,enum MethodIndex index)105 void bindSymbol_l(void* handle, const char* name, enum MethodIndex index) {
106 void* symbol = dlsym(handle, name);
107 ALOGI_IF(symbol == nullptr,
108 "Failed to find symbol '%s' in libcom.android.media.swcodec.apexcodecs.so: %s",
109 name, dlerror());
110 mMethods[index] = symbol;
111 }
112
init()113 bool init() {
114 {
115 RWLock::AutoRLock l(mLock);
116 if (mInit) {
117 return true;
118 }
119 }
120 void* handle = LoadApexCodecs(RTLD_NOW);
121 if (handle == nullptr) {
122 ALOGI("Failed to load libcom.android.media.swcodec.apexcodecs.so: %s", dlerror());
123 return false;
124 }
125
126 RWLock::AutoWLock l(mLock);
127 #undef BIND_SYMBOL
128 #define BIND_SYMBOL(name) bindSymbol_l(handle, #name, k_##name);
129 BIND_SYMBOL(ApexCodec_Buffer_clear);
130 BIND_SYMBOL(ApexCodec_Buffer_create);
131 BIND_SYMBOL(ApexCodec_Buffer_destroy);
132 BIND_SYMBOL(ApexCodec_Buffer_getBufferInfo);
133 BIND_SYMBOL(ApexCodec_Buffer_getConfigUpdates);
134 BIND_SYMBOL(ApexCodec_Buffer_getGraphicBuffer);
135 BIND_SYMBOL(ApexCodec_Buffer_getLinearBuffer);
136 BIND_SYMBOL(ApexCodec_Buffer_getType);
137 BIND_SYMBOL(ApexCodec_Buffer_setConfigUpdates);
138 BIND_SYMBOL(ApexCodec_Buffer_setGraphicBuffer);
139 BIND_SYMBOL(ApexCodec_Buffer_setLinearBuffer);
140 BIND_SYMBOL(ApexCodec_Component_create);
141 BIND_SYMBOL(ApexCodec_Component_destroy);
142 BIND_SYMBOL(ApexCodec_Component_flush);
143 BIND_SYMBOL(ApexCodec_Component_getConfigurable);
144 BIND_SYMBOL(ApexCodec_Component_process);
145 BIND_SYMBOL(ApexCodec_Component_reset);
146 BIND_SYMBOL(ApexCodec_Component_start);
147 BIND_SYMBOL(ApexCodec_Configurable_config);
148 BIND_SYMBOL(ApexCodec_Configurable_query);
149 BIND_SYMBOL(ApexCodec_Configurable_querySupportedParams);
150 BIND_SYMBOL(ApexCodec_Configurable_querySupportedValues);
151 BIND_SYMBOL(ApexCodec_GetComponentStore);
152 BIND_SYMBOL(ApexCodec_ParamDescriptors_destroy);
153 BIND_SYMBOL(ApexCodec_ParamDescriptors_getDescriptor);
154 BIND_SYMBOL(ApexCodec_ParamDescriptors_getIndices);
155 BIND_SYMBOL(ApexCodec_SettingResults_destroy);
156 BIND_SYMBOL(ApexCodec_SettingResults_getResultAtIndex);
157 BIND_SYMBOL(ApexCodec_SupportedValues_destroy);
158 BIND_SYMBOL(ApexCodec_SupportedValues_getTypeAndValues);
159 BIND_SYMBOL(ApexCodec_Traits_get);
160 #undef BIND_SYMBOL
161
162 // Check every symbol is bound.
163 for (int i = 0; i < k_MethodCount; ++i) {
164 if (mMethods[i] == nullptr) {
165 ALOGI("Uninitialized method in "
166 "libcom.android.media.swcodec.apexcodecs_lazy at index: %d", i);
167 return false;
168 }
169 }
170 mInit = true;
171 return true;
172 }
173
174 RWLock mLock;
175 // Table of methods pointers in libcom.android.media.swcodec.apexcodecs APIs.
176 void* mMethods[k_MethodCount];
177 bool mInit{false};
178 };
179
180 } // anonymous namespace
181
182 #define INVOKE_METHOD(name, returnIfNull, args...) \
183 do { \
184 void* method = ApexCodecsLazyLoader::Get().getMethodAt(k_##name); \
185 if (!method) return (returnIfNull); \
186 return reinterpret_cast<decltype(&name)>(method)(args); \
187 } while (0)
188
189 //
190 // Forwarding for methods in ApexCodecs.h.
191 //
192
ApexCodec_GetComponentStore()193 ApexCodec_ComponentStore *ApexCodec_GetComponentStore() {
194 INVOKE_METHOD(ApexCodec_GetComponentStore, nullptr);
195 }
196
ApexCodec_Traits_get(ApexCodec_ComponentStore * store,size_t index)197 ApexCodec_ComponentTraits *ApexCodec_Traits_get(
198 ApexCodec_ComponentStore *store, size_t index) {
199 INVOKE_METHOD(ApexCodec_Traits_get, nullptr, store, index);
200 }
201
ApexCodec_Buffer_create()202 ApexCodec_Buffer *ApexCodec_Buffer_create() {
203 INVOKE_METHOD(ApexCodec_Buffer_create, nullptr);
204 }
205
ApexCodec_Buffer_destroy(ApexCodec_Buffer * buffer)206 void ApexCodec_Buffer_destroy(ApexCodec_Buffer *buffer) {
207 INVOKE_METHOD(ApexCodec_Buffer_destroy, void(), buffer);
208 }
209
ApexCodec_Buffer_clear(ApexCodec_Buffer * buffer)210 void ApexCodec_Buffer_clear(ApexCodec_Buffer *buffer) {
211 INVOKE_METHOD(ApexCodec_Buffer_clear, void(), buffer);
212 }
213
ApexCodec_Buffer_getType(ApexCodec_Buffer * buffer)214 ApexCodec_BufferType ApexCodec_Buffer_getType(ApexCodec_Buffer *buffer) {
215 INVOKE_METHOD(ApexCodec_Buffer_getType, APEXCODEC_BUFFER_TYPE_EMPTY, buffer);
216 }
217
ApexCodec_Buffer_setBufferInfo(ApexCodec_Buffer * _Nonnull buffer,ApexCodec_BufferFlags flags,uint64_t frameIndex,uint64_t timestampUs)218 void ApexCodec_Buffer_setBufferInfo(
219 ApexCodec_Buffer *_Nonnull buffer,
220 ApexCodec_BufferFlags flags,
221 uint64_t frameIndex,
222 uint64_t timestampUs) {
223 INVOKE_METHOD(ApexCodec_Buffer_setBufferInfo, void(),
224 buffer, flags, frameIndex, timestampUs);
225 }
226
ApexCodec_Buffer_setLinearBuffer(ApexCodec_Buffer * buffer,const ApexCodec_LinearBuffer * linearBuffer)227 ApexCodec_Status ApexCodec_Buffer_setLinearBuffer(
228 ApexCodec_Buffer *buffer,
229 const ApexCodec_LinearBuffer *linearBuffer) {
230 INVOKE_METHOD(ApexCodec_Buffer_setLinearBuffer, APEXCODEC_STATUS_OMITTED,
231 buffer, linearBuffer);
232 }
233
ApexCodec_Buffer_setGraphicBuffer(ApexCodec_Buffer * buffer,AHardwareBuffer * graphicBuffer)234 ApexCodec_Status ApexCodec_Buffer_setGraphicBuffer(
235 ApexCodec_Buffer *buffer,
236 AHardwareBuffer *graphicBuffer) {
237 INVOKE_METHOD(ApexCodec_Buffer_setGraphicBuffer, APEXCODEC_STATUS_OMITTED,
238 buffer, graphicBuffer);
239 }
240
ApexCodec_Buffer_setConfigUpdates(ApexCodec_Buffer * buffer,const ApexCodec_LinearBuffer * configUpdates)241 ApexCodec_Status ApexCodec_Buffer_setConfigUpdates(
242 ApexCodec_Buffer *buffer,
243 const ApexCodec_LinearBuffer *configUpdates) {
244 INVOKE_METHOD(ApexCodec_Buffer_setConfigUpdates, APEXCODEC_STATUS_OMITTED,
245 buffer, configUpdates);
246 }
247
ApexCodec_Buffer_getBufferInfo(ApexCodec_Buffer * buffer,ApexCodec_BufferFlags * outFlags,uint64_t * outFrameIndex,uint64_t * outTimestampUs)248 ApexCodec_Status ApexCodec_Buffer_getBufferInfo(
249 ApexCodec_Buffer *buffer,
250 ApexCodec_BufferFlags *outFlags,
251 uint64_t *outFrameIndex,
252 uint64_t *outTimestampUs) {
253 INVOKE_METHOD(ApexCodec_Buffer_getBufferInfo, APEXCODEC_STATUS_OMITTED,
254 buffer, outFlags, outFrameIndex, outTimestampUs);
255 }
256
ApexCodec_Buffer_getLinearBuffer(ApexCodec_Buffer * buffer,ApexCodec_LinearBuffer * outLinearBuffer)257 ApexCodec_Status ApexCodec_Buffer_getLinearBuffer(
258 ApexCodec_Buffer *buffer,
259 ApexCodec_LinearBuffer *outLinearBuffer) {
260 INVOKE_METHOD(ApexCodec_Buffer_getLinearBuffer, APEXCODEC_STATUS_OMITTED,
261 buffer, outLinearBuffer);
262 }
263
ApexCodec_Buffer_getGraphicBuffer(ApexCodec_Buffer * buffer,AHardwareBuffer ** outGraphicBuffer)264 ApexCodec_Status ApexCodec_Buffer_getGraphicBuffer(
265 ApexCodec_Buffer *buffer,
266 AHardwareBuffer **outGraphicBuffer) {
267 INVOKE_METHOD(ApexCodec_Buffer_getGraphicBuffer, APEXCODEC_STATUS_OMITTED,
268 buffer, outGraphicBuffer);
269 }
270
ApexCodec_Buffer_getConfigUpdates(ApexCodec_Buffer * buffer,ApexCodec_LinearBuffer * outConfigUpdates,bool * outOwnedByClient)271 ApexCodec_Status ApexCodec_Buffer_getConfigUpdates(
272 ApexCodec_Buffer *buffer,
273 ApexCodec_LinearBuffer *outConfigUpdates,
274 bool *outOwnedByClient) {
275 INVOKE_METHOD(ApexCodec_Buffer_getConfigUpdates, APEXCODEC_STATUS_OMITTED,
276 buffer, outConfigUpdates, outOwnedByClient);
277 }
ApexCodec_Component_create(ApexCodec_ComponentStore * store,const char * name,ApexCodec_Component ** comp)278 ApexCodec_Status ApexCodec_Component_create(
279 ApexCodec_ComponentStore *store, const char *name, ApexCodec_Component **comp) {
280 INVOKE_METHOD(ApexCodec_Component_create, APEXCODEC_STATUS_OMITTED, store, name, comp);
281 }
282
ApexCodec_Component_destroy(ApexCodec_Component * comp)283 void ApexCodec_Component_destroy(ApexCodec_Component *comp) {
284 INVOKE_METHOD(ApexCodec_Component_destroy, void(), comp);
285 }
286
ApexCodec_Component_start(ApexCodec_Component * comp)287 ApexCodec_Status ApexCodec_Component_start(ApexCodec_Component *comp) {
288 INVOKE_METHOD(ApexCodec_Component_start, APEXCODEC_STATUS_OMITTED, comp);
289 }
290
ApexCodec_Component_flush(ApexCodec_Component * comp)291 ApexCodec_Status ApexCodec_Component_flush(ApexCodec_Component *comp) {
292 INVOKE_METHOD(ApexCodec_Component_flush, APEXCODEC_STATUS_OMITTED, comp);
293 }
294
ApexCodec_Component_reset(ApexCodec_Component * comp)295 ApexCodec_Status ApexCodec_Component_reset(ApexCodec_Component *comp) {
296 INVOKE_METHOD(ApexCodec_Component_reset, APEXCODEC_STATUS_OMITTED, comp);
297 }
298
ApexCodec_Component_getConfigurable(ApexCodec_Component * comp)299 ApexCodec_Configurable *ApexCodec_Component_getConfigurable(
300 ApexCodec_Component *comp) {
301 INVOKE_METHOD(ApexCodec_Component_getConfigurable, nullptr, comp);
302 }
303
ApexCodec_SupportedValues_getTypeAndValues(ApexCodec_SupportedValues * supportedValues,ApexCodec_SupportedValuesType * type,ApexCodec_SupportedValuesNumberType * numberType,ApexCodec_Value ** values,uint32_t * numValues)304 ApexCodec_Status ApexCodec_SupportedValues_getTypeAndValues(
305 ApexCodec_SupportedValues *supportedValues,
306 ApexCodec_SupportedValuesType *type,
307 ApexCodec_SupportedValuesNumberType *numberType,
308 ApexCodec_Value **values,
309 uint32_t *numValues) {
310 INVOKE_METHOD(ApexCodec_SupportedValues_getTypeAndValues, APEXCODEC_STATUS_OMITTED,
311 supportedValues, type, numberType, values, numValues);
312 }
313
ApexCodec_SupportedValues_destroy(ApexCodec_SupportedValues * values)314 void ApexCodec_SupportedValues_destroy(ApexCodec_SupportedValues *values) {
315 INVOKE_METHOD(ApexCodec_SupportedValues_destroy, void(), values);
316 }
317
ApexCodec_SettingResults_getResultAtIndex(ApexCodec_SettingResults * results,size_t index,ApexCodec_SettingResultFailure * failure,ApexCodec_ParamFieldValues * field,ApexCodec_ParamFieldValues ** conflicts,size_t * numConflicts)318 ApexCodec_Status ApexCodec_SettingResults_getResultAtIndex(
319 ApexCodec_SettingResults *results,
320 size_t index,
321 ApexCodec_SettingResultFailure *failure,
322 ApexCodec_ParamFieldValues *field,
323 ApexCodec_ParamFieldValues **conflicts,
324 size_t *numConflicts) {
325 INVOKE_METHOD(ApexCodec_SettingResults_getResultAtIndex, APEXCODEC_STATUS_OMITTED,
326 results, index, failure, field, conflicts, numConflicts);
327 }
328
ApexCodec_SettingResults_destroy(ApexCodec_SettingResults * results)329 void ApexCodec_SettingResults_destroy(ApexCodec_SettingResults *results) {
330 INVOKE_METHOD(ApexCodec_SettingResults_destroy, void(), results);
331 }
332
ApexCodec_Component_process(ApexCodec_Component * comp,const ApexCodec_Buffer * input,ApexCodec_Buffer * output,size_t * consumed,size_t * produced)333 ApexCodec_Status ApexCodec_Component_process(
334 ApexCodec_Component *comp,
335 const ApexCodec_Buffer *input,
336 ApexCodec_Buffer *output,
337 size_t *consumed,
338 size_t *produced) {
339 INVOKE_METHOD(ApexCodec_Component_process, APEXCODEC_STATUS_OMITTED,
340 comp, input, output, consumed, produced);
341 }
342
ApexCodec_Configurable_config(ApexCodec_Configurable * comp,ApexCodec_LinearBuffer * config,ApexCodec_SettingResults ** results)343 ApexCodec_Status ApexCodec_Configurable_config(
344 ApexCodec_Configurable *comp,
345 ApexCodec_LinearBuffer *config,
346 ApexCodec_SettingResults **results) {
347 INVOKE_METHOD(ApexCodec_Configurable_config, APEXCODEC_STATUS_OMITTED, comp, config, results);
348 }
349
ApexCodec_Configurable_query(ApexCodec_Configurable * comp,uint32_t indices[],size_t numIndices,ApexCodec_LinearBuffer * config,size_t * writtenOrRequested)350 ApexCodec_Status ApexCodec_Configurable_query(
351 ApexCodec_Configurable *comp,
352 uint32_t indices[],
353 size_t numIndices,
354 ApexCodec_LinearBuffer *config,
355 size_t *writtenOrRequested) {
356 INVOKE_METHOD(ApexCodec_Configurable_query, APEXCODEC_STATUS_OMITTED,
357 comp, indices, numIndices, config, writtenOrRequested);
358 }
359
ApexCodec_ParamDescriptors_getIndices(ApexCodec_ParamDescriptors * descriptors,uint32_t ** indices,size_t * numIndices)360 ApexCodec_Status ApexCodec_ParamDescriptors_getIndices(
361 ApexCodec_ParamDescriptors *descriptors,
362 uint32_t **indices,
363 size_t *numIndices) {
364 INVOKE_METHOD(ApexCodec_ParamDescriptors_getIndices, APEXCODEC_STATUS_OMITTED,
365 descriptors, indices, numIndices);
366 }
367
ApexCodec_ParamDescriptors_getDescriptor(ApexCodec_ParamDescriptors * descriptors,uint32_t index,ApexCodec_ParamAttribute * attr,const char ** name,uint32_t ** dependencies,size_t * numDependencies)368 ApexCodec_Status ApexCodec_ParamDescriptors_getDescriptor(
369 ApexCodec_ParamDescriptors *descriptors,
370 uint32_t index,
371 ApexCodec_ParamAttribute *attr,
372 const char **name,
373 uint32_t **dependencies,
374 size_t *numDependencies) {
375 INVOKE_METHOD(ApexCodec_ParamDescriptors_getDescriptor, APEXCODEC_STATUS_OMITTED,
376 descriptors, index, attr, name, dependencies, numDependencies);
377 }
378
ApexCodec_ParamDescriptors_destroy(ApexCodec_ParamDescriptors * descriptors)379 void ApexCodec_ParamDescriptors_destroy(
380 ApexCodec_ParamDescriptors *descriptors) {
381 INVOKE_METHOD(ApexCodec_ParamDescriptors_destroy, void(), descriptors);
382 }
383
ApexCodec_Configurable_querySupportedParams(ApexCodec_Configurable * comp,ApexCodec_ParamDescriptors ** descriptors)384 ApexCodec_Status ApexCodec_Configurable_querySupportedParams(
385 ApexCodec_Configurable *comp,
386 ApexCodec_ParamDescriptors **descriptors) {
387 INVOKE_METHOD(ApexCodec_Configurable_querySupportedParams, APEXCODEC_STATUS_OMITTED,
388 comp, descriptors);
389 }
390
ApexCodec_Configurable_querySupportedValues(ApexCodec_Configurable * comp,ApexCodec_SupportedValuesQuery * queries,size_t numQueries)391 ApexCodec_Status ApexCodec_Configurable_querySupportedValues(
392 ApexCodec_Configurable *comp,
393 ApexCodec_SupportedValuesQuery *queries,
394 size_t numQueries) {
395 INVOKE_METHOD(ApexCodec_Configurable_querySupportedValues, APEXCODEC_STATUS_OMITTED,
396 comp, queries, numQueries);
397 }
398