1 /*
2 * Copyright (C) 2022 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 #pragma once
18
19 #include <dlfcn.h>
20 #include <string>
21 #include <unistd.h>
22
23 namespace android::mediautils {
24
25 /**
26 * Returns a shared pointer to the library instance.
27 *
28 * When the last reference to the library is removed, the library will be dlclose().
29 *
30 * Notes:
31 * 1) The Android bionic linker always uses RTLD_GLOBAL for executable linking
32 * which provides the symbols for other subsequent libraries.
33 *
34 * 2) RTLD_GLOBAL like RTLD_NODELETE disables unloading of the library
35 * when the reference count drops to zero.
36 *
37 * 3) RTLD_LOCAL is the default in the absence of RTLD_GLOBAL.
38 * RTLD_LOCAL may be ignored in some situations, for example:
39 * https://stackoverflow.com/questions/56808889/static-objects-destructed-before-dlclose
40 *
41 * 4) We default to use RTLD_LAZY to delay symbol relocations until needed.
42 * This flag may be ignored by Android. RTLD_LAZY may allow
43 * unresolved symbols if not accessed, or symbols added later with another library
44 * loaded with RTLD_GLOBAL. See RTLD_NOW for comparison.
45 *
46 * 5) Avoid both staticly loading and dynamically loading the same library.
47 * This is known to cause double free issues as library symbols may map to
48 * the same location. RTLD_DEEPBIND does not appear supported as of T.
49 * https://stackoverflow.com/questions/34073051/when-we-are-supposed-to-use-rtld-deepbind
50 * https://stackoverflow.com/questions/31209693/static-library-linked-two-times
51 *
52 * Details on Android linker and debugging here:
53 * See: adb shell setprop debug.ld.all dlerror,dlopen,dlsym
54 * See: https://android.googlesource.com/platform/bionic/+/master/android-changes-for-ndk-developers.md
55 *
56 * Some other relevant info:
57 * See: Soong double_loadable:true go/double_loadable
58 * See: https://en.wikipedia.org/wiki/One_Definition_Rule#Summary
59 *
60 * TODO(b/228093151): Consider moving to platform/system.
61 *
62 * \param libraryName
63 * \param flags one of the dlopen RTLD_* flags. https://linux.die.net/man/3/dlopen
64 * \return shared_ptr to the library. This will be nullptr if it isn't found.
65 */
66 std::shared_ptr<void> loadLibrary(const char *libraryName, int flags = RTLD_LAZY);
67
68 /**
69 * Returns a shared pointer to an object in the library
70 *
71 * The object will be a global variable or method in the library.
72 * The object reference counting is aliased to the library shared ptr.
73 *
74 * Note: If any internals of the shared library are exposed, for example by
75 * a method returning a pointer to library globals,
76 * or returning an object whose class definition is from the library,
77 * then the shared_ptr must be kept alive while such references to
78 * library internals exist to prevent library unloading.
79 *
80 * See usage of RTLD_NODELETE as a flag to prevent unloading.
81 *
82 * \param objectName of the library object.
83 * \param library a shared pointer to the library returned by loadLibrary().
84 * \return shared_ptr to the object, but whose refcount is
85 * aliased to the library shared ptr.
86 */
87 std::shared_ptr<void> getUntypedObjectFromLibrary(
88 const char *objectName, const std::shared_ptr<void>& library);
89
90 /**
91 * Returns a shared pointer to an object in the library
92 *
93 * This is the template typed version of getUntypedObjectFromLibrary().
94 *
95 * \param objectName of the library object.
96 * \param library a shared pointer to the library
97 * \return shared_ptr to the object, but whose refcount is
98 * aliased to the library shared ptr.
99 */
100 template <typename T>
getObjectFromLibrary(const char * objectName,const std::shared_ptr<void> & library)101 std::shared_ptr<T> getObjectFromLibrary(
102 const char *objectName, const std::shared_ptr<void>& library) {
103 return std::static_pointer_cast<T>(getUntypedObjectFromLibrary(objectName, library));
104 }
105
106 } // android::mediautils
107