| # Platform APIs |
| |
| The latest version of this document is available at |
| https://android.googlesource.com/platform/ndk/+/master/docs/PlatformApis.md. |
| |
| ## Implications of Adding a New Platform API |
| |
| Before adding a platform API to the NDK, there are some guarantees and |
| restrictions that need to be considered. |
| |
| ### ABI Compatibility |
| |
| The NDK ABI must be forward compatible. Apps that are in the Play Store must |
| continue to function on new devices. This means that once something becomes NDK |
| ABI, it must continue to be exposed and behavior must be preserved by the |
| platform for the lifetime of the ABI (for all intents and purposes, forever). |
| The NDK ABI includes but is not limited to: |
| |
| * Exposed functions and global data. |
| * Layout and size of publicly visible data structures. |
| * Values of constants (such as enums). |
| |
| ### Source Compatibility |
| |
| Source compatibility should be maintained, though exceptions have been made. |
| When appropriate, source compatibility breaking features can be limited to only |
| breaking when the user is targeting at least the API level that broke the change |
| (e.g. `#if __ANDROID_API__ >= 24`), which ensures that any currently building |
| app will continue building until the developer chooses to upgrade to a new |
| platform level. |
| |
| Note that the definition of target API level in the NDK differs from the SDK. |
| For the NDK, the target API level is the minimum supported API level for the |
| app. If any non-ABI features are guarded by the target API level, they will only |
| be available to apps with a minimum target that includes that API level. |
| |
| As a practical example of this, the NDK historically did not expose the `ALOG*` |
| log macros, only the `__android_log_*` functions. If the macros were to be added |
| but only exposed for API levels android-24 and newer, these helper macros that |
| could otherwise be available to Gingerbread would only be usable by developers |
| that chose to forfeit all Android users on devices older than android-24. |
| |
| ### API Restrictions |
| |
| NDK APIs are C APIs only. This restriction may be lifted in the future, but at |
| the moment Android's C++ ABI is not guaranteed to be stable. Note that this does |
| not restrict the implementation of the API to C, only the interface that is |
| exposed in the headers. |
| |
| NDK API headers can only depend on other NDK API headers. Platform headers from |
| android-base, libcutils, libnativehelper, etc are not available to the NDK. |
| |
| ## For Platform Developers |
| |
| To get your API into the NDK you'll generally need to define the two pieces that |
| implement it: the headers and the libraries. Often the library is libandroid.so |
| and you won't need to add a new library, but you'll need to modify an existing |
| one. For this reason, libraries and the headers for those libraries are defined |
| separately. |
| |
| ### Headers |
| |
| To add headers to the NDK, create an `ndk_headers` module in your Android.bp. |
| Examples of this module type can be found in [bionic/libc/Android.bp]. |
| |
| These module definitions are as follows: |
| |
| ``` |
| // Will install $MODULE_PATH/include/foo/bar/baz.h to qux/bar/baz.h (relative to |
| // $NDK_OUT/sysroot/usr/include). |
| ndk_headers { |
| name: "foo", |
| |
| // Base directory of the headers being installed. This path will be stripped |
| // when installed. |
| from: "include/foo", |
| |
| // Install path within the sysroot. |
| to: "qux", |
| |
| // List of headers to install. Relative to the Android.bp. Glob compatible. |
| // The common case is "include/**/*.h". |
| srcs: ["include/foo/bar/baz.h"], |
| |
| // If true, makes the headers available to the platform but hides them from |
| // the NDK release. When actively developing an NDK API, `draft` should be |
| // set to true so the API isn't released until it is ready. It can still be |
| // used within the platform and CTS even if it is a draft. |
| // |
| // Note that false is the default, so when releasing an API this line may |
| // simply be removed. |
| draft: true, |
| } |
| ``` |
| |
| ### Libraries |
| |
| To add a library to the NDK, create an `ndk_library` module in your Android.bp. |
| An example of this module type can be found in [bionic/libc/Android.bp]. |
| |
| These module defintions are as follows: |
| |
| ``` |
| // The name of the generated file will be based on the module name by stripping |
| // the ".ndk" suffix from the module name. Module names must end with ".ndk" |
| // (as a convention to allow soong to guess the NDK name of a dependency when |
| // needed). "libfoo.ndk" will generate "libfoo.so. |
| ndk_library { |
| name: "libfoo.ndk", |
| |
| // A version script with some metadata that encodes version and arch |
| // mappings so that only one script is needed instead of one per API/arch. |
| // An example of this file can be found at [bionic/libc/libc.map.txt]. |
| // |
| // For a new library, this is something you'll need to create yourself. |
| // These should *not* be generated by `readelf -sW`ing your library. The |
| // purpose of these files is to explicitly list your APIs so you never |
| // accidentally expose private API that you'll need to support forever. |
| symbol_file: "libfoo.map.txt", |
| |
| // The first API level a library was available. A library will be generated |
| // for every API level beginning with this one. |
| first_version: "9", |
| |
| // Same behavior as the `draft` property in `ndk_headers`. |
| draft: true, |
| } |
| ``` |
| |
| ### Linker namespaces' public libraries list |
| |
| You wouldn't be adding a library to the NDK unless you actually wanted apps to |
| be able to use your library, but in Android N or later, apps are only allowed |
| to access libraries that are part of the NDK API surface. The list of libraries |
| available to apps is stored in: |
| - `system/core/rootdir/etc/public.libraries.android.txt` for main Android |
| - `system/core/rootdir/etc/public.libraries.wear.txt` for Android Wear |
| devices |
| - `system/core/rootdir/etc/public.libraries.iot.txt` for Android Things devices |
| |
| If a library is specific to either 32 or 64-bit ABI, append `32` or `64` to the |
| line (with space) to specify the bitness. e.g. `libfoo.so 32`. If neither 32 nor |
| 64 is specified, the library is considered to be available for all ABIs of the |
| device. |
| |
| By default, all the libraries listed in the above text file are preloaded when the |
| app process is started. This behavior can be controlled per library by appending |
| `nopreload` option. e.g. `libfoo.so nopreload`. Libraries with the option won't be |
| preloaded, but will be loaded on demand. |
| |
| The `nopreload` option and the bitness option can be used together as in |
| `libfoo.so 32 nopreload`. |
| |
| ### CTS |
| |
| There's also a CTS test to ensure that non-NDK libraries don't get added to |
| the public libraries list. This test can be found at |
| `cts/tests/tests/jni/src/android/jni/cts/LinkerNamespacesHelper.java`. Simply |
| add your library to the `PUBLIC_SYSTEM_LIBRARIES` list in that file. |
| |
| [bionic/libc/Android.bp]: https://android.googlesource.com/platform/bionic/+/master/libc/Android.bp |
| |
| ### Making sure it works |
| |
| The best way to make sure you've set everything up properly is to add a test to |
| CTS. Make sure this test is built using the NDK (make sure `LOCAL_SDK_VERSION` |
| is set, `sdk_version` if you're using Android.bp). If your test passes in CTS |
| when it is built with the NDK, then everything has been set up properly. |
| |
| Note that without this step, it is possible that one of the above steps will |
| have been done incorrectly and you wouldn't know without inspecting everything |
| yourself. If the `ndk_library` rule ends up in an Android.bp that never gets |
| parsed and there are no tests built with the NDK that use that library, your |
| build will still pass. |
| |
| ## For NDK Developers |
| |
| The platform APIs reach the NDK via the "toolchain" module of the NDK (currently |
| via the intermediates of "sysroot" and "platforms". The sysroot currently is |
| just the headers, whereas the libraries are in platforms and CRT objects are |
| built as part of the NDK (an ELF note is added to the CRT objects so NDK |
| binaries contain NDK version information). |
| |
| ### Updating the Sysroot |
| |
| The NDK sysroot is provided as prebuilts in `//prebuilts/ndk/platform`. To |
| update these, use `poetry run update-sysroot` (from the `//ndk` directory). |
| Prebuilts suitable for check-in must be taken from the build servers. However, |
| to test changes that have not yet been submitted to the platform, do the |
| following: |
| |
| ```bash |
| $ cd path/to/platform |
| $ OUT_DIR=ndk-out DIST_DIR=ndk-dist build/soong/scripts/build-ndk-prebuilts.sh |
| $ cd path/to/ndk/ndk |
| $ poetry run update-sysroot --no-download \ |
| path/to/platform/ndk-dist/ndk_platform.tar.bz2 |
| ``` |
| |
| Note that most branches will include at least one codenamed release in the |
| sysroot artifacts. Clang only handles integer API levels, so these directories |
| must be renamed when creating the sysroot. This is done automatically by |
| `update-sysroot` based on the contents of [meta/platforms.json]. |
| |
| [meta/platforms.json]: ../meta/platforms.json |