__INTRODUCED_IN macros add the availability attribute

__INTRODUCED_IN (and its variants) macro is used to mark the
availability of an API symbol. The macros were used by the versioner
tool for the NDK clients. When the Bionic headers are processed by the
tool, APIs with the macros are guarded with __ANDROID_API__. e.g.,

void foo() __INTRDUCED_IN(30);

is processed into

\#if __ANDROID_API__ >= 30
void foo();
\#endif

by the versioner.

The macros however didn't play a role for other cases, e.g. OS
components.

This is too strict for NDK clients and too loose for the non-NDK
clients. For the former, this completely hides the APIs that are newer
than the min sdk version (__ANDROID_API__). For the latter, a call to
such an API can be made without being guarded.

This change is the first step towards a better way of handling the
native APIs availability. The plan is that every NDK APIs are annotated
with the availability attribute and callers are required to guard their
API calls with a runtime check if the API is newer than the min sdk
version of the caller.

In this change, the macros now emits the availability attribute for the
non-NDK clients (i.e. when not processed by versioner).

Bug: 163288375
Bug: 134795810
Test: m
Change-Id: I6eb2bce2bc2770cbfd69815e6816b6f25b3d6127
diff --git a/libc/include/android/versioning.h b/libc/include/android/versioning.h
index 3ea414a..2b9a027 100644
--- a/libc/include/android/versioning.h
+++ b/libc/include/android/versioning.h
@@ -33,13 +33,62 @@
 
 #else
 
-#define __INTRODUCED_IN(api_level)
-#define __DEPRECATED_IN(api_level)
-#define __REMOVED_IN(api_level)
-#define __INTRODUCED_IN_32(api_level)
+// When headers are not processed by the versioner (i.e. compiled into object files),
+// the availability attributed is emitted instead. The clang compiler will make the symbol weak
+// when targeting old api_level and enforce the reference to the symbol to be guarded with
+// __builtin_available(android api_level, *).
+
+// The 'strict' flag is required for NDK clients where the use of "-Wunguarded-availability" cannot
+// be enforced. In the case, the absence of 'strict' makes it possible to call an unavailable API
+// without the __builtin_available check, which will cause a link error at runtime.
+// Android platform build system defines this macro along with -Wunguarded-availability
+#if defined(__ANDROID_UNGUARDED_AVAILABILITY__)
+#define __MAYBE_STRICT
+#else
+#define __MAYBE_STRICT ,strict
+#endif
+
+#define __INTRODUCED_IN(api_level) \
+    __attribute__((availability(android __MAYBE_STRICT,introduced=api_level)))
+#define __DEPRECATED_IN(api_level) \
+    __attribute__((availability(android __MAYBE_STRICT,deprecated=api_level)))
+#define __REMOVED_IN(api_level) \
+    __attribute__((availability(android __MAYBE_STRICT,obsoleted=api_level)))
+
+// The same availability attribute can't be annotated multiple times. Therefore, the macros are
+// defined for the configuration that it is valid for so that declarations like the below doesn't
+// cause inconsistent availability values which is an error with -Wavailability:
+//
+// void foo() __INTRODUCED_IN_32(30) __INTRODUCED_IN_64(31);
+//
+// This also takes the advantage of the fact that we never use bitness-specific macro with
+// arch-specific macro. In other words,
+//
+// void foo() __INTRODUCED_IN_ARM(30) __INTRODUCED_IN_64(31);
+//
+// hasn't been supported and won't be.
+#if !defined(__LP64__)
+#define __INTRODUCED_IN_32(api_level) \
+    __attribute__((availability(android __MAYBE_STRICT,introduced=api_level)))
 #define __INTRODUCED_IN_64(api_level)
+#else
+#define __INTRODUCED_IN_32(api_level)
+#define __INTRODUCED_IN_64(api_level) \
+    __attribute__((availability(android __MAYBE_STRICT,introduced=api_level)))
+#endif
+
+#if defined(__arm__) || defined(__aarch64__)
+#define __INTRODUCED_IN_ARM(api_level) \
+    __attribute__((availability(android __MAYBE_STRICT,introduced=api_level)))
+#define __INTRODUCED_IN_X86(api_level)
+#elif defined(__i386__) || defined(__x86_64__)
+#define __INTRODUCED_IN_ARM(api_level)
+#define __INTRODUCED_IN_X86(api_level) \
+    __attribute__((availability(android __MAYBE_STRICT,introduced=api_level)))
+#else
 #define __INTRODUCED_IN_ARM(api_level)
 #define __INTRODUCED_IN_X86(api_level)
+#endif
 
 #define __VERSIONER_NO_GUARD
 #define __VERSIONER_FORTIFY_INLINE