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;
}