Enable libnativehelper for Windows

This requires using the Windows specific API for loading/manipulating
native libraries, and string printing.
libnativehelper is a dependency of layoutlib native (used for desktop
rendering of Android resources), which is why it needs a Windows verion.

Bug: 117921091
Test: lunch sdk && make libnativehelper
Change-Id: I20fa392ac7e3c031ce076435bf4380205992608b
diff --git a/Android.bp b/Android.bp
index 06f096e..f2340f1 100644
--- a/Android.bp
+++ b/Android.bp
@@ -17,18 +17,33 @@
     host_supported: true,
     export_include_dirs: ["include_jni"],
     vendor_available: true,
+    target: {
+        windows: {
+            enabled: true,
+        },
+    },
 }
 
 cc_library_headers {
     name: "libnativehelper_header_only",
     host_supported: true,
     export_include_dirs: ["header_only_include"],
+    target: {
+        windows: {
+            enabled: true,
+        },
+    },
 }
 
 cc_library_headers {
     name: "jni_platform_headers",
     host_supported: true,
     export_include_dirs: ["platform_include"],
+    target: {
+        windows: {
+            enabled: true,
+        },
+    },
 }
 
 cc_library {
@@ -41,6 +56,7 @@
         "toStringArray.cpp",
     ],
     shared_libs: [
+        "libbase",
         "liblog",
     ],
     cflags: [
@@ -56,6 +72,11 @@
         symbol_file: "libnativehelper.map.txt",
         versions: ["1"],
     },
+    target: {
+        windows: {
+            enabled: true,
+        },
+    },
 }
 
 //
diff --git a/JNIHelp.cpp b/JNIHelp.cpp
index 0cd048d..c82d312 100644
--- a/JNIHelp.cpp
+++ b/JNIHelp.cpp
@@ -71,31 +71,13 @@
     ALOGV("Registering %s's %d native methods...", className, numMethods);
 
     scoped_local_ref<jclass> c(env, findClass(env, className));
-    if (c.get() == NULL) {
-        char* tmp;
-        const char* msg;
-        if (asprintf(&tmp,
-                     "Native registration unable to find class '%s'; aborting...",
-                     className) == -1) {
-            // Allocation failed, print default warning.
-            msg = "Native registration unable to find class; aborting...";
-        } else {
-            msg = tmp;
-        }
-        e->FatalError(msg);
-    }
+    ALOG_ALWAYS_FATAL_IF(c.get() == NULL,
+                         "Native registration unable to find class '%s'; aborting...",
+                         className);
 
-    if ((*env)->RegisterNatives(e, c.get(), gMethods, numMethods) < 0) {
-        char* tmp;
-        const char* msg;
-        if (asprintf(&tmp, "RegisterNatives failed for '%s'; aborting...", className) == -1) {
-            // Allocation failed, print default warning.
-            msg = "RegisterNatives failed; aborting...";
-        } else {
-            msg = tmp;
-        }
-        e->FatalError(msg);
-    }
+    int result = e->RegisterNatives(c.get(), gMethods, numMethods);
+    ALOG_ALWAYS_FATAL_IF(result < 0, "RegisterNatives failed for '%s'; aborting...",
+                         className);
 
     return 0;
 }
@@ -327,9 +309,14 @@
 }  // namespace impl
 
 MODULE_API const char* jniStrError(int errnum, char* buf, size_t buflen) {
+#ifdef _WIN32
+  strerror_s(buf, buflen, errnum);
+  return buf;
+#else
   // The magic of C++ overloading 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);
+#endif
 }
 
 MODULE_API jobject jniCreateFileDescriptor(C_JNIEnv* env, int fd) {
diff --git a/JniInvocation.cpp b/JniInvocation.cpp
index d2229b3..6d992e6 100644
--- a/JniInvocation.cpp
+++ b/JniInvocation.cpp
@@ -16,7 +16,11 @@
 
 #include "nativehelper/JniInvocation.h"
 
+#ifdef _WIN32
+#include <windows.h>
+#else
 #include <dlfcn.h>
+#endif
 #include <stdlib.h>
 #include <string.h>
 
@@ -29,6 +33,7 @@
 #include <sys/system_properties.h>
 #endif
 
+#include "android-base/errors.h"
 #include "JniConstants.h"
 
 namespace {
@@ -55,6 +60,49 @@
 #endif
 }
 
+#ifdef _WIN32
+#define FUNC_POINTER FARPROC
+#else
+#define FUNC_POINTER void*
+#endif
+
+void* OpenLibrary(const char* filename) {
+#ifdef _WIN32
+  return LoadLibrary(filename);
+#else
+  // Load with RTLD_NODELETE in order to ensure that libart.so is not unmapped when it is closed.
+  // This is due to the fact that it is possible that some threads might have yet to finish
+  // exiting even after JNI_DeleteJavaVM returns, which can lead to segfaults if the library is
+  // unloaded.
+  const int kDlopenFlags = RTLD_NOW | RTLD_NODELETE;
+  return dlopen(filename, kDlopenFlags);
+#endif
+}
+
+int CloseLibrary(void* handle) {
+#ifdef _WIN32
+  return FreeLibrary(static_cast<HMODULE>(handle));
+#else
+  return dlclose(handle);
+#endif
+}
+
+FUNC_POINTER GetSymbol(void* handle, const char* symbol) {
+#ifdef _WIN32
+  return GetProcAddress(static_cast<HMODULE>(handle), symbol);
+#else
+  return dlsym(handle, symbol);
+#endif
+}
+
+std::string GetError() {
+#ifdef _WIN32
+  return android::base::SystemErrorCodeToString(GetLastError());
+#else
+  return std::string(dlerror());
+#endif
+}
+
 }  // namespace
 
 struct JniInvocationImpl final {
@@ -81,7 +129,7 @@
   JniInvocationImpl(const JniInvocationImpl&) = delete;
   JniInvocationImpl& operator=(const JniInvocationImpl&) = delete;
 
-  bool FindSymbol(void** pointer, const char* symbol);
+  bool FindSymbol(FUNC_POINTER* pointer, const char* symbol);
 
   static JniInvocationImpl* jni_invocation_;
 
@@ -113,7 +161,7 @@
 JniInvocationImpl::~JniInvocationImpl() {
   jni_invocation_ = NULL;
   if (handle_ != NULL) {
-    dlclose(handle_);
+    CloseLibrary(handle_);
   }
 }
 
@@ -168,16 +216,11 @@
   char* buffer = NULL;
 #endif
   library = GetLibrary(library, buffer);
-  // Load with RTLD_NODELETE in order to ensure that libart.so is not unmapped when it is closed.
-  // This is due to the fact that it is possible that some threads might have yet to finish
-  // exiting even after JNI_DeleteJavaVM returns, which can lead to segfaults if the library is
-  // unloaded.
-  const int kDlopenFlags = RTLD_NOW | RTLD_NODELETE;
-  handle_ = dlopen(library, kDlopenFlags);
+  handle_ = OpenLibrary(library);
   if (handle_ == NULL) {
     if (strcmp(library, kLibraryFallback) == 0) {
       // Nothing else to try.
-      ALOGE("Failed to dlopen %s: %s", library, dlerror());
+      ALOGE("Failed to dlopen %s: %s", library, GetError().c_str());
       return false;
     }
     // Note that this is enough to get something like the zygote
@@ -186,23 +229,23 @@
     // RuntimeInit.commonInit for where we fix up the property to
     // avoid future fallbacks. http://b/11463182
     ALOGW("Falling back from %s to %s after dlopen error: %s",
-          library, kLibraryFallback, dlerror());
+          library, kLibraryFallback, GetError().c_str());
     library = kLibraryFallback;
-    handle_ = dlopen(library, kDlopenFlags);
+    handle_ = OpenLibrary(library);
     if (handle_ == NULL) {
-      ALOGE("Failed to dlopen %s: %s", library, dlerror());
+      ALOGE("Failed to dlopen %s: %s", library, GetError().c_str());
       return false;
     }
   }
-  if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetDefaultJavaVMInitArgs_),
+  if (!FindSymbol(reinterpret_cast<FUNC_POINTER*>(&JNI_GetDefaultJavaVMInitArgs_),
                   "JNI_GetDefaultJavaVMInitArgs")) {
     return false;
   }
-  if (!FindSymbol(reinterpret_cast<void**>(&JNI_CreateJavaVM_),
+  if (!FindSymbol(reinterpret_cast<FUNC_POINTER*>(&JNI_CreateJavaVM_),
                   "JNI_CreateJavaVM")) {
     return false;
   }
-  if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetCreatedJavaVMs_),
+  if (!FindSymbol(reinterpret_cast<FUNC_POINTER*>(&JNI_GetCreatedJavaVMs_),
                   "JNI_GetCreatedJavaVMs")) {
     return false;
   }
@@ -221,11 +264,11 @@
   return JNI_GetCreatedJavaVMs_(vms, size, vm_count);
 }
 
-bool JniInvocationImpl::FindSymbol(void** pointer, const char* symbol) {
-  *pointer = dlsym(handle_, symbol);
+bool JniInvocationImpl::FindSymbol(FUNC_POINTER* pointer, const char* symbol) {
+  *pointer = GetSymbol(handle_, symbol);
   if (*pointer == NULL) {
-    ALOGE("Failed to find symbol %s: %s\n", symbol, dlerror());
-    dlclose(handle_);
+    ALOGE("Failed to find symbol %s: %s\n", symbol, GetError().c_str());
+    CloseLibrary(handle_);
     handle_ = NULL;
     return false;
   }