summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
l---------[-rw-r--r--]android-changes-for-ndk-developers.md420
-rw-r--r--docs/android-changes-for-ndk-developers.md419
2 files changed, 420 insertions, 419 deletions
diff --git a/android-changes-for-ndk-developers.md b/android-changes-for-ndk-developers.md
index 1630db8e4..328d3eb96 100644..120000
--- a/android-changes-for-ndk-developers.md
+++ b/android-changes-for-ndk-developers.md
@@ -1,419 +1 @@
-# Android changes for NDK developers
-
-This document details important changes related to native code
-loading in various Android releases.
-
-Required tools: the NDK has an _arch_-linux-android-readelf binary
-(e.g. arm-linux-androideabi-readelf or i686-linux-android-readelf)
-for each architecture (under toolchains/), but you can use readelf for
-any architecture, as we will be doing basic inspection only. On Linux
-you need to have the “binutils” package installed for readelf,
-and “pax-utils” for scanelf.
-
-
-## How we manage incompatible changes
-
-Our general practice with dynamic linker behavior changes is that they
-will be tied to an app's target API level:
-
-* Below the affected API level we'll preserve the old behavior or issue
-a warning, as appropriate.
-
-* At the affected API level and above, we’ll refuse to load the library.
-
-* Warnings about any behavior change that will affect a library if you
-increase your target API level will appear in logcat when that library
-is loaded, even if you're not yet targeting that API level.
-
-* On a developer preview build, dynamic linker warnings will also show up
-as toasts. Experience has shown that many developers don’t habitually
-check logcat for warnings until their app stops functioning, so the
-toasts help bring some visibility to the issues before it's too late.
-
-## Changes to library dependency resolution
-
-Until it was [fixed](https://issuetracker.google.com/36950617) in
-JB-MR2, Android didn't include the application library directory
-on the dynamic linker's search path. This meant that apps
-had to call `dlopen` or `System.loadLibrary` on all transitive
-dependencies before loading their main library. Worse, until it was
-[fixed](https://issuetracker.google.com/36935779) in JB-MR2, the
-dynamic linker's caching code cached failures too, so it was necessary
-to topologically sort your libraries and load them in reverse order.
-
-If you need to support Android devices running OS
-versions older than JB-MR2, you might want to consider
-[ReLinker](https://github.com/KeepSafe/ReLinker) which claims to solve
-these problems automatically.
-
-## Changes to library search order
-
-We have made various fixes to library search order when resolving symbols.
-
-With API 22, load order switched from depth-first to breadth-first to
-fix dlsym(3).
-
-Before API 23, the default search order was to try the main executable,
-LD_PRELOAD libraries, the library itself, and its DT_NEEDED libraries
-in that order. For API 23 and later, for any given library, the dynamic
-linker divides other libraries into the global group and the local
-group. The global group is shared by all libraries and contains the main
-executable, LD_PRELOAD libraries, and any library with the DF_1_GLOBAL
-flag set (by passing “-z global” to ld(1)). The local group is
-the breadth-first transitive closure of the library and its DT_NEEDED
-libraries. The M dynamic linker searches the global group followed by
-the local group. This allows ASAN, for example, to ensure that it can
-intercept any symbol.
-
-
-## RTLD_LOCAL (Available in API level >= 23)
-
-The dlopen(3) RTLD_LOCAL flag used to be ignored but is implemented
-correctly in API 23 and later. Note that RTLD_LOCAL is the default,
-so even calls to dlopen(3) that didn’t explicitly use RTLD_LOCAL will
-be affected (unless they explicitly used RTLD_GLOBAL). With RTLD_LOCAL,
-symbols will not be made available to libraries loaded by later calls
-to dlopen(3) (as opposed to being referenced by DT_NEEDED entries).
-
-
-## GNU hashes (Availible in API level >= 23)
-
-The GNU hash style available with --hash-style=gnu allows faster
-symbol lookup and is now supported by the dynamic linker in API 23 and
-above. (Use --hash-style=both if you want to build code that uses this
-feature >= Android M but still works on older releases.)
-
-
-## Correct soname/path handling (Available in API level >= 23)
-
-The dynamic linker now understands the difference
-between a library’s soname and its path (public bug
-https://code.google.com/p/android/issues/detail?id=6670). API level 23
-is the first release where search by soname is implemented. Earlier
-releases would assume that the basename of the library was the soname,
-and used that to search for already-loaded libraries. For example,
-`dlopen("/this/directory/does/not/exist/libc.so", RTLD_NOW)` would
-find `/system/lib/libc.so` because it’s already loaded. This also meant
-that it was impossible to have two libraries `"dir1/libx.so"` and
-`"dir2/libx.so"` --- the dynamic linker couldn’t tell the difference
-and would always use whichever was loaded first, even if you explicitly
-tried to load both. This also applied to DT_NEEDED entries.
-
-Some apps have bad DT_NEEDED entries (usually absolute paths on the build
-machine’s file system) that used to work because we ignored everything
-but the basename. These apps will fail to load on API level 23 and above.
-
-
-## Symbol versioning (Available in API level >= 23)
-
-Symbol versioning allows libraries to provide better backwards
-compatibility. For example, if a library author knowingly changes
-the behavior of a function, they can provide two versions in the same
-library so that old code gets the old version and new code gets the new
-version. This is supported in API level 23 and above.
-
-
-## Opening shared libraries directly from an APK
-
-In API level 23 and above, it’s possible to open a .so file directly from
-your APK. Just use `System.loadLibrary("foo")` exactly as normal but set
-`android:extractNativeLibs="false"` in your `AndroidManifest.xml`. In
-older releases, the .so files were extracted from the APK file
-at install time. This meant that they took up space in your APK and
-again in your installation directory (and this was counted against you
-and reported to the user as space taken up by your app). Any .so file
-that you want to load directly from your APK must be page aligned
-(on a 4096-byte boundary) in the zip file and stored uncompressed.
-Current versions of the zipalign tool take care of alignment.
-
-Note that in API level 23 and above dlopen(3) will open a library from
-any zip file, not just your APK. Just give dlopen(3) a path of the form
-"my_zip_file.zip!/libs/libstuff.so". As with APKs, the library must be
-page-aligned and stored uncompressed for this to work.
-
-
-## Private API (Enforced for API level >= 24)
-
-Native libraries must use only public API, and must not link against
-non-NDK platform libraries. Starting with API 24 this rule is enforced and
-applications are no longer able to load non-NDK platform libraries. The
-rule is enforced by the dynamic linker, so non-public libraries
-are not accessible regardless of the way code tries to load them:
-System.loadLibrary, DT_NEEDED entries, and direct calls to dlopen(3)
-will all work exactly the same.
-
-Users should have a consistent app experience across updates,
-and developers shouldn't have to make emergency app updates to
-handle platform changes. For that reason, we recommend against using
-private C/C++ symbols. Private symbols aren't tested as part of the
-Compatibility Test Suite (CTS) that all Android devices must pass. They
-may not exist, or they may behave differently. This makes apps that use
-them more likely to fail on specific devices, or on future releases ---
-as many developers found when Android 6.0 Marshmallow switched from
-OpenSSL to BoringSSL.
-
-In order to reduce the user impact of this transition, we've identified
-a set of libraries that see significant use from Google Play's
-most-installed apps, and that are feasible for us to support in the
-short term (including libandroid_runtime.so, libcutils.so, libcrypto.so,
-and libssl.so). In order to give you more time to transition, we will
-temporarily support these libraries; so if you see a warning that means
-your code will not work in a future release -- please fix it now!
-
-In O and later, the system property `debug.ld.greylist_disabled` can be
-used to deny access to the greylist even to an app that would normally
-be allowed it. This allows you to test compatibility without bumping the
-app's `targetSdkVersion`. Use `setprop debug.ld.greylist_disabled true`
-to turn this on (any other value leaves the greylist enabled).
-
-```
-$ readelf --dynamic libBroken.so | grep NEEDED
- 0x00000001 (NEEDED) Shared library: [libnativehelper.so]
- 0x00000001 (NEEDED) Shared library: [libutils.so]
- 0x00000001 (NEEDED) Shared library: [libstagefright_foundation.so]
- 0x00000001 (NEEDED) Shared library: [libmedia_jni.so]
- 0x00000001 (NEEDED) Shared library: [liblog.so]
- 0x00000001 (NEEDED) Shared library: [libdl.so]
- 0x00000001 (NEEDED) Shared library: [libz.so]
- 0x00000001 (NEEDED) Shared library: [libstdc++.so]
- 0x00000001 (NEEDED) Shared library: [libm.so]
- 0x00000001 (NEEDED) Shared library: [libc.so]
-```
-
-*Potential problems*: starting from API 24 the dynamic linker will not
-load private libraries, preventing the application from loading.
-
-*Resolution*: rewrite your native code to rely only on public API. As a
-short term workaround, platform libraries without complex dependencies
-(libcutils.so) can be copied to the project. As a long term solution
-the relevant code must be copied to the project tree. SSL/Media/JNI
-internal/binder APIs should not be accessed from the native code. When
-necessary, native code should call appropriate public Java API methods.
-
-A complete list of public libraries is available within the NDK, under
-platforms/android-API/usr/lib.
-
-Note: SSL/crypto is a special case, applications must NOT use platform
-libcrypto and libssl libraries directly, even on older platforms. All
-applications should use GMS Security Provider to ensure they are protected
-from known vulnerabilities.
-
-
-## Missing Section Headers (Enforced for API level >= 24)
-
-Each ELF file has additional information contained in the section
-headers. These headers must be present now, because the dynamic linker
-uses them for sanity checking. Some developers strip them in an
-attempt to obfuscate the binary and prevent reverse engineering. (This
-doesn't really help because it is possible to reconstruct the stripped
-information using widely-available tools.)
-
-```
-$ readelf --header libBroken.so | grep 'section headers'
- Start of section headers: 0 (bytes into file)
- Size of section headers: 0 (bytes)
- Number of section headers: 0
-```
-
-*Resolution*: remove the extra steps from your build that strip section
-headers.
-
-## Text Relocations (Enforced for API level >= 23)
-
-Starting with API 23, shared objects must not contain text
-relocations. That is, the code must be loaded as is and must not be
-modified. Such an approach reduces load time and improves security.
-
-The usual reason for text relocations is non-position independent
-hand-written assembler. This is not common. Use the scanelf tool as
-described in our documentation for further diagnostics:
-
-```
-$ scanelf -qT libTextRel.so
- libTextRel.so: (memory/data?) [0x15E0E2] in (optimized out: previous simd_broken_op1) [0x15E0E0]
- libTextRel.so: (memory/data?) [0x15E3B2] in (optimized out: previous simd_broken_op2) [0x15E3B0]
- ...
-```
-
-If you have no scanelf tool available, it is possible to do a basic
-check with readelf instead, look for either a TEXTREL entry or the
-TEXTREL flag. Either alone is sufficient. (The value corresponding to the
-TEXTREL entry is irrelevant and typically 0 --- simply the presence of
-the TEXTREL entry declares that the .so contains text relocations). This
-example has both indicators present:
-
-```
-$ readelf --dynamic libTextRel.so | grep TEXTREL
- 0x00000016 (TEXTREL) 0x0
- 0x0000001e (FLAGS) SYMBOLIC TEXTREL BIND_NOW
-```
-
-Note: it is technically possible to have a shared object with the TEXTREL
-entry/flag but without any actual text relocations. This doesn't happen
-with the NDK, but if you're generating ELF files yourself make sure
-you're not generating ELF files that claim to have text relocations,
-because the Android dynamic linker trusts the entry/flag.
-
-*Potential problems*: Relocations enforce code pages being writable, and
-wastefully increase the number of dirty pages in memory. The dynamic
-linker has issued warnings about text relocations since Android K
-(API 19), but on API 23 and above it refuses to load code with text
-relocations.
-
-*Resolution*: rewrite assembler to be position independent to ensure
-no text relocations are necessary. The
-[Gentoo Textrels guide](https://wiki.gentoo.org/wiki/Hardened/Textrels_Guide)
-has instructions for fixing text relocations, and more detailed
-[scanelf documentation](https://wiki.gentoo.org/wiki/Hardened/PaX_Utilities).
-
-
-## Invalid DT_NEEDED Entries (Enforced for API level >= 23)
-
-While library dependencies (DT_NEEDED entries in the ELF headers) can be
-absolute paths, that doesn't make sense on Android because you have
-no control over where your library will be installed by the system. A
-DT_NEEDED entry should be the same as the needed library's SONAME,
-leaving the business of finding the library at runtime to the dynamic
-linker.
-
-Before API 23, Android's dynamic linker ignored the full path, and
-used only the basename (the part after the last ‘/') when looking
-up the required libraries. Since API 23 the runtime linker will honor
-the DT_NEEDED exactly and so it won't be able to load the library if
-it is not present in that exact location on the device.
-
-Even worse, some build systems have bugs that cause them to insert
-DT_NEEDED entries that point to a file on the build host, something that
-cannot be found on the device.
-
-```
-$ readelf --dynamic libSample.so | grep NEEDED
- 0x00000001 (NEEDED) Shared library: [libm.so]
- 0x00000001 (NEEDED) Shared library: [libc.so]
- 0x00000001 (NEEDED) Shared library: [libdl.so]
- 0x00000001 (NEEDED) Shared library:
-[C:\Users\build\Android\ci\jni\libBroken.so]
-```
-
-*Potential problems*: before API 23 the DT_NEEDED entry's basename was
-used, but starting from API 23 the Android runtime will try to load the
-library using the path specified, and that path won't exist on the
-device. There are broken third-party toolchains/build systems that use
-a path on a build host instead of the SONAME.
-
-*Resolution*: make sure all required libraries are referenced by SONAME
-only. It is better to let the runtime linker to find and load those
-libraries as the location may change from device to device.
-
-
-## Missing SONAME (Enforced for API level >= 23)
-
-Each ELF shared object (“native library”) must have a SONAME (Shared
-Object Name) attribute. The NDK toolchain adds this attribute by default,
-so its absence indicates either a misconfigured alternative toolchain
-or a misconfiguration in your build system. A missing SONAME may lead
-to runtime issues such as the wrong library being loaded: the filename
-is used instead when this attribute is missing.
-
-```
-$ readelf --dynamic libWithSoName.so | grep SONAME
- 0x0000000e (SONAME) Library soname: [libWithSoName.so]
-```
-
-*Potential problems*: namespace conflicts may lead to the wrong library
-being loaded at runtime, which leads to crashes when required symbols
-are not found, or you try to use an ABI-incompatible library that isn't
-the library you were expecting.
-
-*Resolution*: the current NDK generates the correct SONAME by
-default. Ensure you're using the current NDK and that you haven't
-configured your build system to generate incorrect SONAME entries (using
-the -soname linker option).
-
-
-## DT_RUNPATH support (Available in API level >= 24)
-
-If an ELF file contains a DT_RUNPATH entry, the directories listed there
-will be searched to resolve DT_NEEDED entries. The string `${ORIGIN}` will
-be rewritten at runtime to the directory containing the ELF file. This
-allows the use of relative paths. The `${LIB}` and `${PLATFORM}`
-substitutions supported on some systems are not currently implemented on
-Android.
-
-
-## Writable and Executable Segments (Enforced for API level >= 26)
-
-Each segment in an ELF file has associated flags that tell the
-dynamic linker what permissions to give the corresponding page in
-memory. For security, data shouldn't be executable and code shouldn't be
-writable. This means that the W (for Writable) and E (for Executable)
-flags should be mutually exclusive. This wasn't historically enforced,
-but is now.
-
-```
-$ readelf --program-headers -W libBadFlags.so | grep WE
- LOAD 0x000000 0x00000000 0x00000000 0x4c01d 0x4c01d RWE 0x1000
-```
-
-*Resolution*: we're aware of one middleware product that introduces these
-into your app. The middleware vendor is aware of the problem and has a fix
-available.
-
-## Invalid ELF header/section headers (Enforced for API level >= 26)
-
-In API level 26 and above the dynamic linker checks more values in
-the ELF header and section headers and fails if they are invalid.
-
-*Example error*
-```
-dlopen failed: "/data/data/com.example.bad/lib.so" has unsupported e_shentsize: 0x0 (expected 0x28)
-```
-
-*Resolution*: don't use tools that produce invalid/malformed
-ELF files. Note that using them puts application under high risk of
-being incompatible with future versions of Android.
-
-## Enable logging of dlopen/dlsym and library loading errors for apps (Available in Android O)
-
-Starting with Android O it is possible to enable logging of dynamic
-linker activity for debuggable apps by setting a property corresponding
-to the fully-qualified name of the specific app:
-```
-adb shell setprop debug.ld.app.com.example.myapp dlerror,dlopen,dlsym
-adb logcat
-```
-
-Any combination of `dlerror`, `dlopen`, and `dlsym` can be used. There's
-no separate `dlclose` option: `dlopen` covers both loading and unloading
-of libraries. Note also that `dlerror` doesn't correspond to actual
-calls of dlerror(3) but to any time the dynamic linker writes to its
-internal error buffer, so you'll see any errors the dynamic linker would
-have reported, even if the code you're debugging doesn't actually call
-dlerror(3) itself.
-
-On userdebug and eng builds it is possible to enable tracing for the
-whole system by using the `debug.ld.all` system property instead of
-app-specific one. For example, to enable logging of all dlopen(3)
-(and thus dclose(3)) calls, and all failures, but not dlsym(3) calls:
-```
-adb shell setprop debug.ld.all dlerror,dlopen
-```
-
-## dlclose interacts badly with thread local variables with non-trivial destructors
-
-Android allows `dlclose` to unload a library even if there are still
-thread-local variables with non-trivial destructors. This leads to
-crashes when a thread exits and attempts to call the destructor, the
-code for which has been unloaded (as in [issue 360], fixed in P).
-
-[issue 360]: https://github.com/android-ndk/ndk/issues/360
-
-Not calling `dlclose` or ensuring that your library has `RTLD_NODELETE`
-set (so that calls to `dlclose` don't actually unload the library)
-are possible workarounds.
-
-| | Pre-M | M+ | P+ |
-| ----------------- | -------------------------- | ------- | ----- |
-| No workaround | Works for static STL | Broken | Works |
-| `-Wl,-z,nodelete` | Works for static STL | Works | Works |
-| No `dlclose` | Works | Works | Works |
+docs/android-changes-for-ndk-developers.md \ No newline at end of file
diff --git a/docs/android-changes-for-ndk-developers.md b/docs/android-changes-for-ndk-developers.md
new file mode 100644
index 000000000..1630db8e4
--- /dev/null
+++ b/docs/android-changes-for-ndk-developers.md
@@ -0,0 +1,419 @@
+# Android changes for NDK developers
+
+This document details important changes related to native code
+loading in various Android releases.
+
+Required tools: the NDK has an _arch_-linux-android-readelf binary
+(e.g. arm-linux-androideabi-readelf or i686-linux-android-readelf)
+for each architecture (under toolchains/), but you can use readelf for
+any architecture, as we will be doing basic inspection only. On Linux
+you need to have the “binutils” package installed for readelf,
+and “pax-utils” for scanelf.
+
+
+## How we manage incompatible changes
+
+Our general practice with dynamic linker behavior changes is that they
+will be tied to an app's target API level:
+
+* Below the affected API level we'll preserve the old behavior or issue
+a warning, as appropriate.
+
+* At the affected API level and above, we’ll refuse to load the library.
+
+* Warnings about any behavior change that will affect a library if you
+increase your target API level will appear in logcat when that library
+is loaded, even if you're not yet targeting that API level.
+
+* On a developer preview build, dynamic linker warnings will also show up
+as toasts. Experience has shown that many developers don’t habitually
+check logcat for warnings until their app stops functioning, so the
+toasts help bring some visibility to the issues before it's too late.
+
+## Changes to library dependency resolution
+
+Until it was [fixed](https://issuetracker.google.com/36950617) in
+JB-MR2, Android didn't include the application library directory
+on the dynamic linker's search path. This meant that apps
+had to call `dlopen` or `System.loadLibrary` on all transitive
+dependencies before loading their main library. Worse, until it was
+[fixed](https://issuetracker.google.com/36935779) in JB-MR2, the
+dynamic linker's caching code cached failures too, so it was necessary
+to topologically sort your libraries and load them in reverse order.
+
+If you need to support Android devices running OS
+versions older than JB-MR2, you might want to consider
+[ReLinker](https://github.com/KeepSafe/ReLinker) which claims to solve
+these problems automatically.
+
+## Changes to library search order
+
+We have made various fixes to library search order when resolving symbols.
+
+With API 22, load order switched from depth-first to breadth-first to
+fix dlsym(3).
+
+Before API 23, the default search order was to try the main executable,
+LD_PRELOAD libraries, the library itself, and its DT_NEEDED libraries
+in that order. For API 23 and later, for any given library, the dynamic
+linker divides other libraries into the global group and the local
+group. The global group is shared by all libraries and contains the main
+executable, LD_PRELOAD libraries, and any library with the DF_1_GLOBAL
+flag set (by passing “-z global” to ld(1)). The local group is
+the breadth-first transitive closure of the library and its DT_NEEDED
+libraries. The M dynamic linker searches the global group followed by
+the local group. This allows ASAN, for example, to ensure that it can
+intercept any symbol.
+
+
+## RTLD_LOCAL (Available in API level >= 23)
+
+The dlopen(3) RTLD_LOCAL flag used to be ignored but is implemented
+correctly in API 23 and later. Note that RTLD_LOCAL is the default,
+so even calls to dlopen(3) that didn’t explicitly use RTLD_LOCAL will
+be affected (unless they explicitly used RTLD_GLOBAL). With RTLD_LOCAL,
+symbols will not be made available to libraries loaded by later calls
+to dlopen(3) (as opposed to being referenced by DT_NEEDED entries).
+
+
+## GNU hashes (Availible in API level >= 23)
+
+The GNU hash style available with --hash-style=gnu allows faster
+symbol lookup and is now supported by the dynamic linker in API 23 and
+above. (Use --hash-style=both if you want to build code that uses this
+feature >= Android M but still works on older releases.)
+
+
+## Correct soname/path handling (Available in API level >= 23)
+
+The dynamic linker now understands the difference
+between a library’s soname and its path (public bug
+https://code.google.com/p/android/issues/detail?id=6670). API level 23
+is the first release where search by soname is implemented. Earlier
+releases would assume that the basename of the library was the soname,
+and used that to search for already-loaded libraries. For example,
+`dlopen("/this/directory/does/not/exist/libc.so", RTLD_NOW)` would
+find `/system/lib/libc.so` because it’s already loaded. This also meant
+that it was impossible to have two libraries `"dir1/libx.so"` and
+`"dir2/libx.so"` --- the dynamic linker couldn’t tell the difference
+and would always use whichever was loaded first, even if you explicitly
+tried to load both. This also applied to DT_NEEDED entries.
+
+Some apps have bad DT_NEEDED entries (usually absolute paths on the build
+machine’s file system) that used to work because we ignored everything
+but the basename. These apps will fail to load on API level 23 and above.
+
+
+## Symbol versioning (Available in API level >= 23)
+
+Symbol versioning allows libraries to provide better backwards
+compatibility. For example, if a library author knowingly changes
+the behavior of a function, they can provide two versions in the same
+library so that old code gets the old version and new code gets the new
+version. This is supported in API level 23 and above.
+
+
+## Opening shared libraries directly from an APK
+
+In API level 23 and above, it’s possible to open a .so file directly from
+your APK. Just use `System.loadLibrary("foo")` exactly as normal but set
+`android:extractNativeLibs="false"` in your `AndroidManifest.xml`. In
+older releases, the .so files were extracted from the APK file
+at install time. This meant that they took up space in your APK and
+again in your installation directory (and this was counted against you
+and reported to the user as space taken up by your app). Any .so file
+that you want to load directly from your APK must be page aligned
+(on a 4096-byte boundary) in the zip file and stored uncompressed.
+Current versions of the zipalign tool take care of alignment.
+
+Note that in API level 23 and above dlopen(3) will open a library from
+any zip file, not just your APK. Just give dlopen(3) a path of the form
+"my_zip_file.zip!/libs/libstuff.so". As with APKs, the library must be
+page-aligned and stored uncompressed for this to work.
+
+
+## Private API (Enforced for API level >= 24)
+
+Native libraries must use only public API, and must not link against
+non-NDK platform libraries. Starting with API 24 this rule is enforced and
+applications are no longer able to load non-NDK platform libraries. The
+rule is enforced by the dynamic linker, so non-public libraries
+are not accessible regardless of the way code tries to load them:
+System.loadLibrary, DT_NEEDED entries, and direct calls to dlopen(3)
+will all work exactly the same.
+
+Users should have a consistent app experience across updates,
+and developers shouldn't have to make emergency app updates to
+handle platform changes. For that reason, we recommend against using
+private C/C++ symbols. Private symbols aren't tested as part of the
+Compatibility Test Suite (CTS) that all Android devices must pass. They
+may not exist, or they may behave differently. This makes apps that use
+them more likely to fail on specific devices, or on future releases ---
+as many developers found when Android 6.0 Marshmallow switched from
+OpenSSL to BoringSSL.
+
+In order to reduce the user impact of this transition, we've identified
+a set of libraries that see significant use from Google Play's
+most-installed apps, and that are feasible for us to support in the
+short term (including libandroid_runtime.so, libcutils.so, libcrypto.so,
+and libssl.so). In order to give you more time to transition, we will
+temporarily support these libraries; so if you see a warning that means
+your code will not work in a future release -- please fix it now!
+
+In O and later, the system property `debug.ld.greylist_disabled` can be
+used to deny access to the greylist even to an app that would normally
+be allowed it. This allows you to test compatibility without bumping the
+app's `targetSdkVersion`. Use `setprop debug.ld.greylist_disabled true`
+to turn this on (any other value leaves the greylist enabled).
+
+```
+$ readelf --dynamic libBroken.so | grep NEEDED
+ 0x00000001 (NEEDED) Shared library: [libnativehelper.so]
+ 0x00000001 (NEEDED) Shared library: [libutils.so]
+ 0x00000001 (NEEDED) Shared library: [libstagefright_foundation.so]
+ 0x00000001 (NEEDED) Shared library: [libmedia_jni.so]
+ 0x00000001 (NEEDED) Shared library: [liblog.so]
+ 0x00000001 (NEEDED) Shared library: [libdl.so]
+ 0x00000001 (NEEDED) Shared library: [libz.so]
+ 0x00000001 (NEEDED) Shared library: [libstdc++.so]
+ 0x00000001 (NEEDED) Shared library: [libm.so]
+ 0x00000001 (NEEDED) Shared library: [libc.so]
+```
+
+*Potential problems*: starting from API 24 the dynamic linker will not
+load private libraries, preventing the application from loading.
+
+*Resolution*: rewrite your native code to rely only on public API. As a
+short term workaround, platform libraries without complex dependencies
+(libcutils.so) can be copied to the project. As a long term solution
+the relevant code must be copied to the project tree. SSL/Media/JNI
+internal/binder APIs should not be accessed from the native code. When
+necessary, native code should call appropriate public Java API methods.
+
+A complete list of public libraries is available within the NDK, under
+platforms/android-API/usr/lib.
+
+Note: SSL/crypto is a special case, applications must NOT use platform
+libcrypto and libssl libraries directly, even on older platforms. All
+applications should use GMS Security Provider to ensure they are protected
+from known vulnerabilities.
+
+
+## Missing Section Headers (Enforced for API level >= 24)
+
+Each ELF file has additional information contained in the section
+headers. These headers must be present now, because the dynamic linker
+uses them for sanity checking. Some developers strip them in an
+attempt to obfuscate the binary and prevent reverse engineering. (This
+doesn't really help because it is possible to reconstruct the stripped
+information using widely-available tools.)
+
+```
+$ readelf --header libBroken.so | grep 'section headers'
+ Start of section headers: 0 (bytes into file)
+ Size of section headers: 0 (bytes)
+ Number of section headers: 0
+```
+
+*Resolution*: remove the extra steps from your build that strip section
+headers.
+
+## Text Relocations (Enforced for API level >= 23)
+
+Starting with API 23, shared objects must not contain text
+relocations. That is, the code must be loaded as is and must not be
+modified. Such an approach reduces load time and improves security.
+
+The usual reason for text relocations is non-position independent
+hand-written assembler. This is not common. Use the scanelf tool as
+described in our documentation for further diagnostics:
+
+```
+$ scanelf -qT libTextRel.so
+ libTextRel.so: (memory/data?) [0x15E0E2] in (optimized out: previous simd_broken_op1) [0x15E0E0]
+ libTextRel.so: (memory/data?) [0x15E3B2] in (optimized out: previous simd_broken_op2) [0x15E3B0]
+ ...
+```
+
+If you have no scanelf tool available, it is possible to do a basic
+check with readelf instead, look for either a TEXTREL entry or the
+TEXTREL flag. Either alone is sufficient. (The value corresponding to the
+TEXTREL entry is irrelevant and typically 0 --- simply the presence of
+the TEXTREL entry declares that the .so contains text relocations). This
+example has both indicators present:
+
+```
+$ readelf --dynamic libTextRel.so | grep TEXTREL
+ 0x00000016 (TEXTREL) 0x0
+ 0x0000001e (FLAGS) SYMBOLIC TEXTREL BIND_NOW
+```
+
+Note: it is technically possible to have a shared object with the TEXTREL
+entry/flag but without any actual text relocations. This doesn't happen
+with the NDK, but if you're generating ELF files yourself make sure
+you're not generating ELF files that claim to have text relocations,
+because the Android dynamic linker trusts the entry/flag.
+
+*Potential problems*: Relocations enforce code pages being writable, and
+wastefully increase the number of dirty pages in memory. The dynamic
+linker has issued warnings about text relocations since Android K
+(API 19), but on API 23 and above it refuses to load code with text
+relocations.
+
+*Resolution*: rewrite assembler to be position independent to ensure
+no text relocations are necessary. The
+[Gentoo Textrels guide](https://wiki.gentoo.org/wiki/Hardened/Textrels_Guide)
+has instructions for fixing text relocations, and more detailed
+[scanelf documentation](https://wiki.gentoo.org/wiki/Hardened/PaX_Utilities).
+
+
+## Invalid DT_NEEDED Entries (Enforced for API level >= 23)
+
+While library dependencies (DT_NEEDED entries in the ELF headers) can be
+absolute paths, that doesn't make sense on Android because you have
+no control over where your library will be installed by the system. A
+DT_NEEDED entry should be the same as the needed library's SONAME,
+leaving the business of finding the library at runtime to the dynamic
+linker.
+
+Before API 23, Android's dynamic linker ignored the full path, and
+used only the basename (the part after the last ‘/') when looking
+up the required libraries. Since API 23 the runtime linker will honor
+the DT_NEEDED exactly and so it won't be able to load the library if
+it is not present in that exact location on the device.
+
+Even worse, some build systems have bugs that cause them to insert
+DT_NEEDED entries that point to a file on the build host, something that
+cannot be found on the device.
+
+```
+$ readelf --dynamic libSample.so | grep NEEDED
+ 0x00000001 (NEEDED) Shared library: [libm.so]
+ 0x00000001 (NEEDED) Shared library: [libc.so]
+ 0x00000001 (NEEDED) Shared library: [libdl.so]
+ 0x00000001 (NEEDED) Shared library:
+[C:\Users\build\Android\ci\jni\libBroken.so]
+```
+
+*Potential problems*: before API 23 the DT_NEEDED entry's basename was
+used, but starting from API 23 the Android runtime will try to load the
+library using the path specified, and that path won't exist on the
+device. There are broken third-party toolchains/build systems that use
+a path on a build host instead of the SONAME.
+
+*Resolution*: make sure all required libraries are referenced by SONAME
+only. It is better to let the runtime linker to find and load those
+libraries as the location may change from device to device.
+
+
+## Missing SONAME (Enforced for API level >= 23)
+
+Each ELF shared object (“native library”) must have a SONAME (Shared
+Object Name) attribute. The NDK toolchain adds this attribute by default,
+so its absence indicates either a misconfigured alternative toolchain
+or a misconfiguration in your build system. A missing SONAME may lead
+to runtime issues such as the wrong library being loaded: the filename
+is used instead when this attribute is missing.
+
+```
+$ readelf --dynamic libWithSoName.so | grep SONAME
+ 0x0000000e (SONAME) Library soname: [libWithSoName.so]
+```
+
+*Potential problems*: namespace conflicts may lead to the wrong library
+being loaded at runtime, which leads to crashes when required symbols
+are not found, or you try to use an ABI-incompatible library that isn't
+the library you were expecting.
+
+*Resolution*: the current NDK generates the correct SONAME by
+default. Ensure you're using the current NDK and that you haven't
+configured your build system to generate incorrect SONAME entries (using
+the -soname linker option).
+
+
+## DT_RUNPATH support (Available in API level >= 24)
+
+If an ELF file contains a DT_RUNPATH entry, the directories listed there
+will be searched to resolve DT_NEEDED entries. The string `${ORIGIN}` will
+be rewritten at runtime to the directory containing the ELF file. This
+allows the use of relative paths. The `${LIB}` and `${PLATFORM}`
+substitutions supported on some systems are not currently implemented on
+Android.
+
+
+## Writable and Executable Segments (Enforced for API level >= 26)
+
+Each segment in an ELF file has associated flags that tell the
+dynamic linker what permissions to give the corresponding page in
+memory. For security, data shouldn't be executable and code shouldn't be
+writable. This means that the W (for Writable) and E (for Executable)
+flags should be mutually exclusive. This wasn't historically enforced,
+but is now.
+
+```
+$ readelf --program-headers -W libBadFlags.so | grep WE
+ LOAD 0x000000 0x00000000 0x00000000 0x4c01d 0x4c01d RWE 0x1000
+```
+
+*Resolution*: we're aware of one middleware product that introduces these
+into your app. The middleware vendor is aware of the problem and has a fix
+available.
+
+## Invalid ELF header/section headers (Enforced for API level >= 26)
+
+In API level 26 and above the dynamic linker checks more values in
+the ELF header and section headers and fails if they are invalid.
+
+*Example error*
+```
+dlopen failed: "/data/data/com.example.bad/lib.so" has unsupported e_shentsize: 0x0 (expected 0x28)
+```
+
+*Resolution*: don't use tools that produce invalid/malformed
+ELF files. Note that using them puts application under high risk of
+being incompatible with future versions of Android.
+
+## Enable logging of dlopen/dlsym and library loading errors for apps (Available in Android O)
+
+Starting with Android O it is possible to enable logging of dynamic
+linker activity for debuggable apps by setting a property corresponding
+to the fully-qualified name of the specific app:
+```
+adb shell setprop debug.ld.app.com.example.myapp dlerror,dlopen,dlsym
+adb logcat
+```
+
+Any combination of `dlerror`, `dlopen`, and `dlsym` can be used. There's
+no separate `dlclose` option: `dlopen` covers both loading and unloading
+of libraries. Note also that `dlerror` doesn't correspond to actual
+calls of dlerror(3) but to any time the dynamic linker writes to its
+internal error buffer, so you'll see any errors the dynamic linker would
+have reported, even if the code you're debugging doesn't actually call
+dlerror(3) itself.
+
+On userdebug and eng builds it is possible to enable tracing for the
+whole system by using the `debug.ld.all` system property instead of
+app-specific one. For example, to enable logging of all dlopen(3)
+(and thus dclose(3)) calls, and all failures, but not dlsym(3) calls:
+```
+adb shell setprop debug.ld.all dlerror,dlopen
+```
+
+## dlclose interacts badly with thread local variables with non-trivial destructors
+
+Android allows `dlclose` to unload a library even if there are still
+thread-local variables with non-trivial destructors. This leads to
+crashes when a thread exits and attempts to call the destructor, the
+code for which has been unloaded (as in [issue 360], fixed in P).
+
+[issue 360]: https://github.com/android-ndk/ndk/issues/360
+
+Not calling `dlclose` or ensuring that your library has `RTLD_NODELETE`
+set (so that calls to `dlclose` don't actually unload the library)
+are possible workarounds.
+
+| | Pre-M | M+ | P+ |
+| ----------------- | -------------------------- | ------- | ----- |
+| No workaround | Works for static STL | Broken | Works |
+| `-Wl,-z,nodelete` | Works for static STL | Works | Works |
+| No `dlclose` | Works | Works | Works |