Enable libnativehelper with linux_bionic
Making libnativehelper work with linux_bionic required giving
JNIHelp.cpp a more robust way of dealing with the differences between
glibc strerror_r and bionic/posix strerror_r.
Test: build
Test: run linux_bionic gtests
Bug: 31559095
Change-Id: I840f8c912f8a70c2afdaf7a1f2083e7b1f33c546
diff --git a/JNIHelp.cpp b/JNIHelp.cpp
index 88e968b..407f9a1 100644
--- a/JNIHelp.cpp
+++ b/JNIHelp.cpp
@@ -14,13 +14,6 @@
* limitations under the License.
*/
-#if defined(__ANDROID__)
-/* libnativehelper is built by NDK 19 in one variant, which doesn't yet have the GNU strerror_r. */
-#undef _GNU_SOURCE
-/* ...but this code uses asprintf, which is a BSD/GNU extension. */
-#define _BSD_SOURCE
-#endif
-
#define LOG_TAG "JNIHelp"
#include <nativehelper/JniConstants.h>
@@ -360,13 +353,31 @@
__android_log_write(priority, tag, trace.c_str());
}
-const char* jniStrError(int errnum, char* buf, size_t buflen) {
-#if __GLIBC__
- // Note: glibc has a nonstandard strerror_r that returns char* rather than POSIX's int.
- // char *strerror_r(int errnum, char *buf, size_t n);
- return strerror_r(errnum, buf, buflen);
-#else
- int rc = strerror_r(errnum, buf, buflen);
+// Note: glibc has a nonstandard strerror_r that returns char* rather than POSIX's int.
+// char *strerror_r(int errnum, char *buf, size_t n);
+//
+// Some versions of bionic support the glibc style call. Since the set of defines that determine
+// which version is used is byzantine in its complexity we will just use this C++ template hack to
+// select the correct jniStrError implementation based on the libc being used.
+namespace impl {
+
+template<typename StrerrorReturn>
+inline static const char* realJniStrError(StrerrorReturn func,
+ int errnum,
+ char* buf,
+ size_t buflen);
+
+using GNUStrError = char* (*)(int,char*,size_t);
+using POSIXStrError = int (*)(int,char*,size_t);
+
+template<>
+inline const char* realJniStrError(GNUStrError func, int errnum, char* buf, size_t buflen) {
+ return func(errnum, buf, buflen);
+}
+
+template<>
+inline const char* realJniStrError(POSIXStrError func, int errnum, char* buf, size_t buflen) {
+ int rc = func(errnum, buf, buflen);
if (rc != 0) {
// (POSIX only guarantees a value other than 0. The safest
// way to implement this function is to use C++ and overload on the
@@ -374,7 +385,13 @@
snprintf(buf, buflen, "errno %d", errnum);
}
return buf;
-#endif
+}
+} // namespace impl
+
+const char* jniStrError(int errnum, char* buf, size_t buflen) {
+ // The magic of C++ templates selects the correct implementation based on the declared type of
+ // strerror_r. The inline will ensure that we don't have any indirect calls.
+ return impl::realJniStrError(strerror_r, errnum, buf, buflen);
}
jobject jniCreateFileDescriptor(C_JNIEnv* env, int fd) {