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) {