修改R代码遇到Lint tool的报错,搜到了这篇文档,aosp仓库地址:Android NDK API Guidelines。
975a589 Merge changes Iae957d87,I1c52d7bb by Alan Viverette · 11 days ago master
58e9b5f Project import generated by Copybara. by Android API Council · 9 months ago
c0b835d Initial empty repository by Baligh Uddin · 8 years ago
提交记录显示最近才更新的,是官方的NDK应用程序接口规范。软件架构涉及app与系统框架的native部分,语言是c/c++。java和kotlin的编码规范在隔壁的Android API Guidelines文档中。
考虑到我们开发中倾向直接使用和理解英文,一些术语、关键词此处也迎合这种习惯不作翻译。本文是手册性质文档,比较直白,所以本文仅给出标题的翻译。如果读者为熟悉Android native开发,相信在看过标题之后,其段落内容会很快得到理解,所以不必要做损失本味的翻译工作了。
以下是原文。
有的平台代码一开始就没有严格的规范指导,导致一些既有的API可能与当前的规范冲突,这是让本文规范落地的难点之一。在某些情况下,正确的选择是与周围的代码风格保持一致,而不是此处列出的理想规则。
本规范尚在迭代中,将来会随着API review而添加其他规则。
有关这些构建要求的更多信息,请参见: https://android.googlesource.com/platform/ndk/+/master/docs/PlatformApis.md
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.
__BEGIN_DECLS
and __END_DECLS
from sys/cdefs.h
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:
For example:
enum Foo : int16_t { One, Two, Three };
Foo transformFoo(Foo param);
Wrap new methods in #if __ANDROID_API__ >= <api_level>
& #endif
pairs
Mark methods with __INTRODUCED_IN(<api_level>);
Example:
#if __ANDROID_API__ >= 30
binder_status_t AIBinder_getExtension(AIBinder* binder, AIBinder** outExt) __INTRODUCED_IN(30);
#endif
#if __ANDROID_API__ >= <api_level>
. This makes opportunistic usage via dlsym harder to do.<number>
.”<name>.map.txt
with the symbol being exported# introduced=<api_level>
sdk_version
in the Android.bp (LOCAL_SDK_VERSION
for Android.mk) for the testOpaque 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.
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 header defines an enum or constant, that value is forever.
Primitive types like long can have varying sizes. This can lead to issues on 32-bit vs. 64-bit builds.
int32_t
, int64_t
, etc...size_t
int32_t
or int64_t
for enum params/returns.
int32_t
.off_t
.
off_t
can vary based on the definition of _FILE_OFFSET_BITS
. API MUST NOT use off_t
and MUST use off64_t
instead.AClassName
for the typestruct AIBinder;
typedef struct AIBinder AIBinder;
AClassName_methodName
namingAClassName_CallbackType
naming convention.AClassName_SubType
naming conventionAs 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对象和native对象应尽可能具有其各自环境固有的生命周期,并且与其他环境无关。
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
后缀。JNI interop APIs should be in their own header with a trailing _jni
suffix.
Example: asset_manager.h
and asset_manager_jni.h
This helps apps to keep a clean JNI layer in their own code
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.
{.numbered}
If a method cannot fail, the return type should simply be the output or void if there is no output.
{.numbered}
对于分配/访问方法,其中唯一有意义的失败是内存不足或类似的,返回指针并对错误使用NULL。
Example: only failure is ENOMEM
: AMediaDataSource* AMediaDataSource_new();
Example: only failure is not set: ALooper* ALooper_forThread();
{.numbered}
size_t AList_getSize(const AList*);
status_t AList_getSize(const AList*, const size_t* outSize);
{.numbered}
For example, in system_fonts.cpp:
bool AFont_isItalic(const AFont* font) {
LOG_ALWAYS_FATAL_IF(font == nullptr, "nullptr passed as font argument");
return font->mItalic;
}
to_string
method to stringify them.void*
。setCallback
术语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.
register
/unregister
术语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.
_Nonnull
或 _Nullable
Document parameters & return values with _Nonnull
or _Nullable
as appropriate.
These are defined in clang, see https://clang.llvm.org/docs/AttributeReference.html#nullability-attributes
Const
const
For example if a method is a simple getter for an opaque type, the struct pointer argument should be marked const
.
Example:
size_t AList_getSize(const AList*);
size_t AList_getSize(AList*);
_create
而不是 _new
Prefer _create
over _new
as it works better with _createFrom
specializations
_destroy
_acquire
/_release
而不是 _inc
/_dec
for ref count naming原文:https://www.cnblogs.com/houser0323/p/14730734.html