| 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"], |
| } |
| ``` |
| |
| ### 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", |
| } |
| ``` |
| |
| ### 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 on a specific whitelist of NDK libraries. This list is |
| stored in `system/core/rootdir/etc/public.libraries.android.txt` with another |
| subset in `system/core/rootdir/etc/public.libraries.wear.txt` for Android Wear |
| devices. |
| |
| ### 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 "sysroot" and "platforms" modules in |
| checkbuild.py. The sysroot currently is just the headers, whereas the libraries |
| and CRT objects are in platforms. |
| |
| The sysroot module is copied from `prebuilts/ndk/platform/sysroot`. These |
| prebuilts are updated with `prebuilts/ndk/update_platform.py`, which pulls NDK |
| artifacts from the build servers. |
| |
| The platforms module is built partially from `prebuilts/ndk/platform/sysroot` |
| and partially from `development/ndk/platforms`. The former contains the library |
| stubs from the platform, and the latter contains the deprecated headers, the CRT |
| objects, and static libraries. For more information on this process, see |
| [Generating Sysroots](GeneratingSysroots.md). |
| |
| ### Updating the Sysroot |
| |
| The NDK sysroot is provided as prebuilts in prebuilts/ndk/platform. To update |
| these, use prebuilts/ndk/update\_platform.py. 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/prebuilts/ndk |
| $ ./update_platform.py --no-download \ |
| path/to/platform/ndk-dist/ndk_platform.tar.bz2 |
| ``` |