- Android NDK Native APIs
- On this page
- Overview
- Major Native API Updates
- Android API level 3
- C library
- C++ library
- Android-specific log support
- ZLib compression library
- Dynamic linker library
- Android API level 4
- OpenGL ES 1.x Library
- Android API level 5
- OpenGL ES 2.0 library:
- Android API level 8
- jnigraphics
- Android API level 9
- OpenSL ES
- Android native application APIs
- Android API level 14
- OpenMAX AL
- OpenSL ES
- Android API level 18
- OpenGL ES 3.0
- Android API level 21
- OpenGL ES 3.1
- Android NDK API Guidelines
- Contents
- API Rules
- Compatibility
- Headers Must be C Compatible
- APIs must be tagged with the API Level
- Types & enums should be documented with the API level added
- Export map must be tagged with the API level
- NDK APIs must have CTS tests
- Documentation
- APIs must be well documented
- ABI stability guidelines
- Prefer opaque structs
- malloc/free must come from the same build artifact
- Constants are forever
- Prefer fixed-size types
- API Design Guidelines
- Naming conventions
- JNI interop methods should exclusively be in the NDK
- Java objects and native objects should use separate respective lifecycles
- JNI interop APIs should be in their own header with a trailing _jni suffix.
- Errno values should not be propagated across the JNI boundary
- Error Handling
- Methods that cannot fail If a method cannot fail, the return type should simply be the output or void if there is no output. allocation/accessor methods For allocation/accessor methods where the only meaningful failure is out of memory or similar, return the pointer and use NULL for errors. Example: only failure is ENOMEM : AMediaDataSource* AMediaDataSource_new(); Example: only failure is not set: ALooper* ALooper_forThread(); Methods with non-trivial error possibilities For methods with a non-trivial error possibility or multiple unique error types, use an error return value and use an output parameter to return any results For APIs where the only error possibility is the result of a trivial check, such as a basic getter method where the only failure is a nullptr, do not introduce an error handling path but instead abort on bad parameters. Include a quality abort message Error return types should be stringifiable Error return types should have a to_string method to stringify them. The returned strings should be constants. Invalid inputs to the stringify method should return nullptr. Callbacks Callbacks should be a bare function pointer. Callbacks should take a void* for caller-provided context. Use “callback(s)” instead of “listener(s)” For single callback APIs, use setCallback terminology If the API only allows for a single callback to be set, use “setCallback” terminology In such a case, the void* must be passed to both the setCallback method as well as passed to the callback on invoke. To clear the callback, allow setCallback to take NULL to clear. For multiple callback APIs, use register / unregister terminology If the API allows for multiple callbacks to be set, use register/unregister terminology In such a case, the void* is needed on registerCallback, invoke, and unregisterCallback. Register & unregister must use the pair of function pointer + void as the unique key*. As in, it must support registering the same function pointer with different void* userData. Nullability Document and use _Nonnull or _Nullable Document parameters & return values with _Nonnull or _Nullable as appropriate. Use Const Use const when appropriate For example if a method is a simple getter for an opaque type, the struct pointer argument should be marked const . AFoo_create vs. AFoo_new Prefer _create over _new Prefer _create over _new as it works better with _createFrom specializations Источник
- allocation/accessor methods For allocation/accessor methods where the only meaningful failure is out of memory or similar, return the pointer and use NULL for errors. Example: only failure is ENOMEM : AMediaDataSource* AMediaDataSource_new(); Example: only failure is not set: ALooper* ALooper_forThread(); Methods with non-trivial error possibilities For methods with a non-trivial error possibility or multiple unique error types, use an error return value and use an output parameter to return any results For APIs where the only error possibility is the result of a trivial check, such as a basic getter method where the only failure is a nullptr, do not introduce an error handling path but instead abort on bad parameters. Include a quality abort message Error return types should be stringifiable Error return types should have a to_string method to stringify them. The returned strings should be constants. Invalid inputs to the stringify method should return nullptr. Callbacks Callbacks should be a bare function pointer. Callbacks should take a void* for caller-provided context. Use “callback(s)” instead of “listener(s)” For single callback APIs, use setCallback terminology If the API only allows for a single callback to be set, use “setCallback” terminology In such a case, the void* must be passed to both the setCallback method as well as passed to the callback on invoke. To clear the callback, allow setCallback to take NULL to clear. For multiple callback APIs, use register / unregister terminology If the API allows for multiple callbacks to be set, use register/unregister terminology In such a case, the void* is needed on registerCallback, invoke, and unregisterCallback. Register & unregister must use the pair of function pointer + void as the unique key*. As in, it must support registering the same function pointer with different void* userData. Nullability Document and use _Nonnull or _Nullable Document parameters & return values with _Nonnull or _Nullable as appropriate. Use Const Use const when appropriate For example if a method is a simple getter for an opaque type, the struct pointer argument should be marked const . AFoo_create vs. AFoo_new Prefer _create over _new Prefer _create over _new as it works better with _createFrom specializations Источник
- Methods with non-trivial error possibilities For methods with a non-trivial error possibility or multiple unique error types, use an error return value and use an output parameter to return any results For APIs where the only error possibility is the result of a trivial check, such as a basic getter method where the only failure is a nullptr, do not introduce an error handling path but instead abort on bad parameters. Include a quality abort message Error return types should be stringifiable Error return types should have a to_string method to stringify them. The returned strings should be constants. Invalid inputs to the stringify method should return nullptr. Callbacks Callbacks should be a bare function pointer. Callbacks should take a void* for caller-provided context. Use “callback(s)” instead of “listener(s)” For single callback APIs, use setCallback terminology If the API only allows for a single callback to be set, use “setCallback” terminology In such a case, the void* must be passed to both the setCallback method as well as passed to the callback on invoke. To clear the callback, allow setCallback to take NULL to clear. For multiple callback APIs, use register / unregister terminology If the API allows for multiple callbacks to be set, use register/unregister terminology In such a case, the void* is needed on registerCallback, invoke, and unregisterCallback. Register & unregister must use the pair of function pointer + void as the unique key*. As in, it must support registering the same function pointer with different void* userData. Nullability Document and use _Nonnull or _Nullable Document parameters & return values with _Nonnull or _Nullable as appropriate. Use Const Use const when appropriate For example if a method is a simple getter for an opaque type, the struct pointer argument should be marked const . AFoo_create vs. AFoo_new Prefer _create over _new Prefer _create over _new as it works better with _createFrom specializations Источник
- Include a quality abort message Error return types should be stringifiable Error return types should have a to_string method to stringify them. The returned strings should be constants. Invalid inputs to the stringify method should return nullptr. Callbacks Callbacks should be a bare function pointer. Callbacks should take a void* for caller-provided context. Use “callback(s)” instead of “listener(s)” For single callback APIs, use setCallback terminology If the API only allows for a single callback to be set, use “setCallback” terminology In such a case, the void* must be passed to both the setCallback method as well as passed to the callback on invoke. To clear the callback, allow setCallback to take NULL to clear. For multiple callback APIs, use register / unregister terminology If the API allows for multiple callbacks to be set, use register/unregister terminology In such a case, the void* is needed on registerCallback, invoke, and unregisterCallback. Register & unregister must use the pair of function pointer + void as the unique key*. As in, it must support registering the same function pointer with different void* userData. Nullability Document and use _Nonnull or _Nullable Document parameters & return values with _Nonnull or _Nullable as appropriate. Use Const Use const when appropriate For example if a method is a simple getter for an opaque type, the struct pointer argument should be marked const . AFoo_create vs. AFoo_new Prefer _create over _new Prefer _create over _new as it works better with _createFrom specializations Источник
- Error return types should be stringifiable
- Callbacks
- Callbacks should be a bare function pointer.
- Callbacks should take a void* for caller-provided context.
- Use “callback(s)” instead of “listener(s)”
- For single callback APIs, use setCallback terminology
- For multiple callback APIs, use register / unregister terminology
- Nullability
- Document and use _Nonnull or _Nullable
- Use Const
- Use const when appropriate
- AFoo_create vs. AFoo_new
- Prefer _create over _new
Android NDK Native APIs
On this page
The Android NDK provides a set of native headers and shared library files that has gradually increased with successive releases of new Android API levels. This page explains these headers and files, and maps them to specific Android API levels.
Overview
There are two basic steps to enable your app to use the libraries that the NDK provides:
- Include in your code the headers associated with the libraries you wish to use.
- Tell the build system that your native module needs to link against the libraries at load time. For example, to link against /system/lib/libfoo.so , add the following line to your Android.mk file:
To list multiple libraries, use a space as a delimiter. For more information about using the LOCAL_LDLIBS variable, see Android.mk.
For all API levels, the build system automatically links the standard C libraries, the standard C++ libraries, real-time extensions, and pthread ; you do not need to include them when defining your LOCAL_LDLIBS variable. For more information about the C and C++ libraries, see Android API level 3.
Table 1 shows the correspondence between NDK-supported API levels and Android releases.
Table 1. NDK-supported API levels and corresponding Android releases.
NDK-supported API level | Android release |
---|---|
3 | 1.5 |
4 | 1.6 |
5 | 2.0 |
8 | 2.2 |
9 | 2.3 through 3.0.x |
12 | 3.1.x |
13 | 3.2 |
14 | 4.0 through 4.0.2 |
15 | 4.0.3 and 4.0.4 |
16 | 4.1 and 4.1.1 |
17 | 4.2 and 4.2.2 |
18 | 4.3 |
19 | 4.4 |
21 | 4.4W and 5.0 |
Each new release of NDK headers and libraries for a given Android API level is cumulative; you are nearly always safe if you use the most recently released headers when building your app. For example, you can use the NDK headers for Android API level 21 for an app targeting API level 16. By doing so, however, you increase your APK’s footprint.
For more information about Android API levels, see What is API Level?.
Major Native API Updates
Android API level 3
The NDK provides the following APIs for developing native code that runs on Android 1.5 system images and above.
C library
The C library headers for Android 1.5 are available through their standard names, such as stdlib.h and stdio.h . If a header is missing at build time, it’s because the header is not available on the 1.5 system image.
C++ library
An extremely minimal C++ support API is available. For more information on C++ library support, see C++ Library Support.
Android-specific log support
You can write your own wrapper macros to access this functionality. If you wish to perform logging, your native module should link to /system/lib/liblog.so . Implement this linking by including the following line in your Android.mk file:
ZLib compression library
You can use the Zlib compression library by including zlib.h and zconf.h . You must also link your native module against /system/lib/libz.so by including the following line in your Android.mk file:
Dynamic linker library
You can access the Android dynamic linker’s dlopen() , dlsym() , and dlclose() functions by including dlfcn.h . You must also link against /system/lib/libdl.so by including the following line in your Android.mk file:
Android API level 4
The NDK provides the following APIs for developing native code that runs on Android 1.6 system images and above.
OpenGL ES 1.x Library
The standard OpenGL ES headers gl.h and glext.h contain the declarations necessary for performing OpenGL ES 1.x rendering calls from native code.
To use these headers, link your native module to /system/lib/libGLESv1_CM.so by including the following line in your Android.mk file:
All Android-based devices support OpenGL ES 1.0, because Android provides an Open GL 1.0-capable software renderer that can be used on devices without GPUs.
Only Android devices that have the necessary GPU fully support OpenGL ES 1.1. An app can query the OpenGL ES version string and extension string to determine whether the current device supports the features it needs. For information on how to perform this query, see the description of glGetString() in the OpenGL specification.
Additionally, you must put a tag in your manifest file to indicate the version of OpenGL ES that your application requires.
The EGL APIs are only available starting from API level 9. You can, however, use the VM to perform some of the operations that you would get from those APIS. These operations include surface creation and flipping. For an example of how to use GLSurfaceView , see Introducing GLSurfaceView.
The san-angeles sample application provides an example of how to perform these operations, rendering each frame in native code. This sample is a small Android port of the excellent San Angeles Observation demo program.
Android API level 5
The NDK provides the following APIs for developing native code that runs on Android 2.0 system images and above.
OpenGL ES 2.0 library:
The standard OpenGL ES 2.0 headers and contain the declarations needed for performing OpenGL ES 2.0 rendering calls from native code. These rendering calls provide the ability to use the GLSL language to define and use vertex and fragment shaders.
To use OpenGL ES 2.0, link your native module to /system/lib/libGLESv2.so by including the following line in your Android.mk file:
Not all devices support OpenGL ES 2.0. An app can query the OpenGL ES version string and extension string to determine whether the current device supports the features it needs. For information on how to perform this query, see the description of glGetString() in the OpenGL specification.
Additionally, you must put a tag in your manifest file to indicate which version of OpenGL ES your application requires. For more information about the OpenGL ES settings for , see OpenGL ES.
The hello-gl2 sample application provies a basic example of how to use OpenGL ES 2.0 with the NDK.
The EGL APIs are only available starting from API level 9. You can, however, use the VM to perform some of the operations that you would get from those APIs. These operations include surface creation and flipping. For an example of how to use GLSurfaceView , see Introducing GLSurfaceView.
Note: The Android emulator does not support OpenGL ES 2.0 hardware emulation. Running and testing code that uses this API requires a real device with hardware that can support OpenGL ES 2.0.
Android API level 8
The NDK provides the following APIs for developing native code that runs on Android 2.2 system images and above.
jnigraphics
The jnigraphics library exposes a C-based interface that allows native code to reliably access the pixel buffers of Java bitmap objects. The workflow for using jnigraphics is as follows:
- Use AndroidBitmap_getInfo() to retrieve information from JNI, such as width and height, about a given bitmap handle.
- Use AndroidBitmap_lockPixels() to lock the pixel buffer and retrieve a pointer to it. Doing so ensures that the pixels do not move until the app calls AndroidBitmap_unlockPixels() .
- In native code, modify the pixel buffer as appropriate for its pixel format, width, and other characteristics.
- Call AndroidBitmap_unlockPixels() to unlock the buffer.
To use jnigraphics , include the header in your source code, and link against jnigraphics by including the following line in your Android.mk file:
Additional details about this feature are in the comments of the bitmap.h file.
Android API level 9
The NDK provides the following APIs for developing native code that runs on Android 2.3 system images and above.
EGL provides a native platform interface for allocating and managing OpenGLES surfaces. For more information about its features, see EGL Native Platform Interface.
EGL allows you to perform the following operations from native code:
- List supported EGL configurations.
- Allocate and release OpenGLES surfaces.
- Swap or flip surfaces.
The following headers provide EGL functionality:
- EGL/egl.h : the main EGL API definitions.
- EGL/eglext.h : EGL extension-related definitions.
To link against the system’s EGL library, add the following line to your Android.mk file:
OpenSL ES
Android native audio handling is based on the Khronos Group OpenSL ES 1.0.1 API.
The standard OpenSL ES headers OpenSLES.h and OpenSLES_Platform.h contain the declarations necessary for performing audio input and output from the native side of Android. The NDK distribution of the OpenSL ES also provides Android-specific extensions. For information about these extensions, see the comments in OpenSLES_Android.h and OpenSLES_AndroidConfiguration.h .
The system library libOpenSLES.so implements the public native audio functions. Link against it by adding the following line to your Android.mk file:
For more information about the OpenSL ES API, refer to $NDK/docs/Additional_library_docs/opensles/index.html , where $NDK is your NDK installation root directory.
Android native application APIs
Starting from API level 9, you can write an entire Android app with native code, without using any Java.
Note: Writing your app in native code is not, in itself, enough for your app to run in the VM. Moreover, your app must still access most features of the Android platform via JNI.
This release provides the following native headers:
For more information about these headers, see the NDK API Reference documentation, as well as the comments in the headers, themselves. Also, for more information about the larger topic of writing native apps, see Native Activities and Applications.
When you include one or more of these headers, you must also link against the libandroid.so library. To link against libandroid.so , include the following line in your Android.mk file:
Android API level 14
The NDK provides the following APIs for developing native code that runs on Android 4.0 system images and above.
OpenMAX AL
Android native multimedia handling is based on Khronos Group OpenMAX AL 1.0.1 API.
The standard OpenMAX AL headers and contain the declarations necessary for performing multimedia output from the native side of Android.
The NDK distribution of OpenMAX AL also provides Android-specific extensions. For information about these extensions, see the comments in OpenMAXAL_Android.h .
The system library libOpenMAXAL.so implements the public native multimedia functions. To link against this library, include the following line in your Android.mk file:
For more information about this topic, see $NDK/docs/openmaxal/index.html , where $NDK is the root directory of your NDK installation.
OpenSL ES
OpenSL ES support for this Android API level adds PCM support. For more information about OpenSL ES support in the NDK, see OpenSL ES.
Android API level 18
The NDK provides the following APIs for developing native code that runs on Android 4.3 system images and above.
OpenGL ES 3.0
The standard OpenGL ES 3.0 headers gl3.h and gl3ext.h contain the declarations needed for performing OpenGL ES 3.0 rendering calls from native code. These rendering calls provide the ability to use the GLSL language to define and use vertex and fragment shaders.
To use OpenGL ES 3.0, link your native module against /system/lib/libGLESv3.so by including the following line in your Android.mk file:
Not all devices support OpenGL ES 3.0. An app can query the OpenGL ES version string and extension string to determine whether the current device supports the features it needs. For information on how to perform this query, see the description of glGetString() in the OpenGL specification.
Additionally, you must put a tag in your manifest file to indicate which version of OpenGL ES your application requires. For more information about the OpenGL ES settings for , see OpenGL ES.
The gles3jni sample application provides a basic example of how to use OpenGL ES 3.0 with the NDK.
Note: The Android emulator does not support OpenGL ES 3.0 hardware emulation. Running and testing code that uses this API requires a real device with hardware that can support OpenGL ES 3.0.
Android API level 21
The NDK provides the following APIs for developing native code that runs on Android 4.3 system images and above.
OpenGL ES 3.1
The standard OpenGL ES 3.1 headers gl31.h and gl3ext.h contain the declarations needed for performing OpenGL ES 3.1 rendering calls from native code. These rendering calls provide the ability to use the GLSL language to define and use vertex and fragment shaders.
To use OpenGL ES 3.1, link your native module against /system/lib/libGLESv3.so by including the following line in your Android.mk file:
Not all devices support OpenGL ES 3.1. An app can query the OpenGL ES version string and extension string to determine whether the current device supports the features it needs. For information on how to perform this query, see the description of glGetString() in the OpenGL specification.
Additionally, you must put a tag in your manifest file to indicate which version of OpenGL ES your application requires. For more information about the OpenGL ES settings for , see OpenGL ES.
The gles3jni sample application provides a basic example of how to use OpenGL ES 3.1 with the NDK.
Note: The Android emulator does not support OpenGL ES 3.1 hardware emulation. Running and testing code that uses this API requires a real device with hardware that can support OpenGL ES 3.1.
Источник
Android NDK API Guidelines
Contents
API Rules
One of the difficulties in concrete rules is applying them to a platform that was developed without strict guidelines from the beginning, so some of the existing APIs may not adhere. In some cases, the right choice might be to go with what is consistent with APIs in the same general area of the code, rather than in the ideal rules laid out herein.
The rules are a work in progress and will be added to in the future as other patterns emerge from future API reviews.
Compatibility
Headers Must be C Compatible
Even if it is not expected that C is ever used directly, C is the common denominator of (nearly) all FFI systems & tools. It also has a simpler stable ABI story than C++, making it required for NDK’s ABI stability requirements.
Wrap in __BEGIN_DECLS and __END_DECLS from sys/cdefs.h
Non-typedef’ed structs must be used as struct type not just type
Prefer typedef’ing structs, see the Naming Conventions section for more details.
For APEX APIs, this requirement can be relaxed. The ABI exposed must still be C (the header must be contained in an extern “C” block), but the header can make use of the following C++ features:
- Sized-enums which can then also be used as parameters & return values safely.
APIs must be tagged with the API Level
Wrap new methods in #if __ANDROID_API__ >= & #endif pairs
Mark methods with __INTRODUCED_IN();
Types & enums should be documented with the API level added
Types & enum declaration MUST NOT be guarded by #if __ANDROID_API__ >= . This makes opportunistic usage via dlsym harder to do.
Instead their documentation should include what API level they were added in with a comment saying “Introduced in API .”
Export map must be tagged with the API level
Libraries must have a .map.txt with the symbol being exported
Symbols must be marked with # introduced=
- Can be either on each individual symbol or on a version block.
NDK APIs must have CTS tests
All NDK APIs are required to be covered by at least one CTS test.
The CTS test must be built against the NDK proper
- No includes of framework/ paths
- Must set an sdk_version in the Android.bp ( LOCAL_SDK_VERSION for Android.mk) for the test
Documentation
APIs must be well documented
If error return codes are being used, the possible errors must be listed as well.
Thread-safe and thread-hostile objects/methods must be called out explicitly as such.
Object lifetime must be documented for anything that’s not a standard new/free pair.
If ref counting is being used, methods that acquire/release a reference must be documented** as such.
ABI stability guidelines
Prefer opaque structs
Opaque structs allow for size changes more naturally and are generally less fragile.
An exception to this is if the type is inherently fixed. For example ARect is not an opaque struct as a rectangle is inherently 4 fields: left, top, right, bottom. Defining an HTTP header as a struct < const char* key; const char* value; >would also be appropriate, as HTTP headers are inherently fixed.
malloc/free must come from the same build artifact
Different build artifacts may, and often do, have different implementations of malloc/free.
For example: Chrome may opt to use a different allocator for all of Chrome’s code, however the NDK libraries it uses will be using the platform’s default allocator. These may not match, and cannot free memory allocated by the other.
If a library allocates something, such as an opaque struct, it must also provide a free function.
If a library takes ownership of an allocation, it must also take the free function.
Constants are forever
If a header defines an enum or constant, that value is forever.
For defined steppings in a range (such as priority levels or trim memory levels), leave gaps in the numberings for future refinement.
For return codes, have static_asserts or similar to ensure the values are never accidentally changed.
For configuration data, such as default timeouts, use a getter method or an extern variable instead.
Prefer fixed-size types
Primitive types like long can have varying sizes. This can lead to issues on 32-bit vs. 64-bit builds.
In general, prefer instead the fixed-size types int32_t , int64_t , etc.
For counts of things, use size_t
If libc has an existing preference, use that instead (eg, use pid_t if you’re taking a process ID)
Use int32_t or int64_t for enum params/returns.
- The backing size of an enum is technically up to the compiler. As such, even if a parameter or return value represents an enum use instead a fixed-type like int32_t .
- While annoying, a C++ wrapper can also trivially fix this. The compatibility risks are not worth it otherwise.
Avoid off_t .
- The size of an off_t can vary based on the definition of _FILE_OFFSET_BITS . API MUST NOT use off_t and MUST use off64_t instead.
API Design Guidelines
Naming conventions
Prefer AClassName for the type
Typedef by default, for example:
Class methods should follow AClassName_methodName naming
Callbacks should follow a AClassName_CallbackType naming convention.
“Nested” classes should also follow a AClassName_SubType naming convention
JNI interop methods should exclusively be in the NDK
As in, always do AObject_fromJava(JNIEnv, jobject) in the NDK rather than having a long Object#getNativePointer() in the SDK.
Similarly do instead jobject AObject_toJava(JNIEnv, AObject*) in the NDK rather than new Object(long nativePtr); in the SDK.
It is recommended to have JNI interop APIs.
Java objects and native objects should use separate respective lifecycles
To the extent possible, the Java objects and the native objects should have lifecycles native to their respective environments & independent of the other environment.
That is, if a native handle is created from a Java object then the Java object’s lifecycle should not be relevant to the native handle. Similarly, if a Java object is created from a native object the native object should not need to out-live the Java one.
Typically this means both the NDK & Java types should sit on a ref-count system to handle this if the underlying instance is shared.
If the interop just does a copy of the data (such as for a trivial type), then nothing special needs to happen.
Exceptions can be made if it’s impractical for the underlying type to be referenced counted and it’s already scoped to a constrained lifecycle. For example, AParcel_fromJavaParcel adopts the lifecycle of the jobject and as such does not have a corresponding free. This is OK as the lifecycle of a Parcel is already scoped to the duration of a method call in general anyway, so a normal JNI LocalRef will have suitable lifetime for typical usage.
JNI interop APIs should be in their own header with a trailing _jni suffix.
JNI interop APIs should be in their own header with a trailing _jni suffix.
This helps apps to keep a clean JNI layer in their own code
Errno values should not be propagated across the JNI boundary
Errno values, such as EINVAL, are only constant for a given arch+abi combination. As such, they should not be propagated across the JNI boundary as specific literal numbers as the Java-side would lose its arch/abi portability. Java code can, however, use the OsConstants class to refer to errno values. As in, if AFOO_ERROR_BAR is defined as being EINVAL, then it must only be referred to by EINVAL and not by the literal constant 22.
Error Handling
Methods that cannot fail
If a method cannot fail, the return type should simply be the output or void if there is no output.
allocation/accessor methods
For allocation/accessor methods where the only meaningful failure is out of memory or similar, return the pointer and use NULL for errors.
Example: only failure is ENOMEM : AMediaDataSource* AMediaDataSource_new();
Example: only failure is not set: ALooper* ALooper_forThread();
Methods with non-trivial error possibilities
For methods with a non-trivial error possibility or multiple unique error types, use an error return value and use an output parameter to return any results
For APIs where the only error possibility is the result of a trivial check, such as a basic getter method where the only failure is a nullptr, do not introduce an error handling path but instead abort on bad parameters.
Include a quality abort message Error return types should be stringifiable
Error return types should have a to_string method to stringify them.
The returned strings should be constants.
Invalid inputs to the stringify method should return nullptr.
Callbacks
Callbacks should be a bare function pointer.
Callbacks should take a void* for caller-provided context.
Use “callback(s)” instead of “listener(s)”
For single callback APIs, use setCallback terminology
If the API only allows for a single callback to be set, use “setCallback” terminology
In such a case, the void* must be passed to both the setCallback method as well as passed to the callback on invoke.
To clear the callback, allow setCallback to take NULL to clear.
For multiple callback APIs, use register / unregister terminology
If the API allows for multiple callbacks to be set, use register/unregister terminology
In such a case, the void* is needed on registerCallback, invoke, and unregisterCallback.
Register & unregister must use the pair of function pointer + void as the unique key*. As in, it must support registering the same function pointer with different void* userData.
Nullability
Document and use _Nonnull or _Nullable
Document parameters & return values with _Nonnull or _Nullable as appropriate.
Use Const
Use const when appropriate
For example if a method is a simple getter for an opaque type, the struct pointer argument should be marked const .
AFoo_create vs. AFoo_new
Prefer _create over _new
Prefer _create over _new as it works better with _createFrom specializations
Источник