Add JNI Invocation API to libnativehelper
Change-Id: I15870937ad7bfa4757e21f83acbbb6a7826a0b0b
diff --git a/Android.mk b/Android.mk
index 11ba0a3..8a30e5b 100644
--- a/Android.mk
+++ b/Android.mk
@@ -18,6 +18,7 @@
local_src_files := \
JNIHelp.cpp \
JniConstants.cpp \
+ JniInvocation.cpp \
toStringArray.cpp
@@ -30,10 +31,10 @@
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := libnativehelper
-
+LOCAL_CFLAGS := -Werror
LOCAL_C_INCLUDES := external/stlport/stlport bionic/ bionic/libstdc++/include libcore/include
-LOCAL_SHARED_LIBRARIES += libstlport
-
+LOCAL_SHARED_LIBRARIES += libcutils libstlport libdl
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
include $(BUILD_SHARED_LIBRARY)
@@ -45,6 +46,9 @@
LOCAL_MODULE := libnativehelper
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(local_src_files)
+LOCAL_CFLAGS := -Werror
LOCAL_C_INCLUDES := libcore/include
LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_LDFLAGS := -ldl
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
include $(BUILD_HOST_SHARED_LIBRARY)
diff --git a/JniInvocation.cpp b/JniInvocation.cpp
new file mode 100644
index 0000000..08277f0
--- /dev/null
+++ b/JniInvocation.cpp
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "JniInvocation.h"
+
+#include <dlfcn.h>
+#include <stdlib.h>
+
+#include <cstddef>
+
+#define LOG_TAG "JniInvocation"
+#include "cutils/log.h"
+
+#ifdef HAVE_ANDROID_OS
+#include "cutils/properties.h"
+#endif
+
+JniInvocation* JniInvocation::jni_invocation_ = NULL;
+
+JniInvocation::JniInvocation() :
+ handle_(NULL),
+ JNI_GetDefaultJavaVMInitArgs_(NULL),
+ JNI_CreateJavaVM_(NULL),
+ JNI_GetCreatedJavaVMs_(NULL) {
+
+ LOG_ALWAYS_FATAL_IF(jni_invocation_ != NULL, "JniInvocation instance already initialized");
+ jni_invocation_ = this;
+}
+
+JniInvocation::~JniInvocation() {
+ jni_invocation_ = NULL;
+ if (handle_ != NULL) {
+ dlclose(handle_);
+ }
+}
+
+bool JniInvocation::Init(const char* library) {
+#ifdef HAVE_ANDROID_OS
+ char default_library[PROPERTY_VALUE_MAX];
+ property_get("dalvik.vm.lib", default_library, "libdvm.so");
+#else
+ const char* default_library = "libdvm.so";
+#endif
+ if (library == NULL) {
+ library = default_library;
+ }
+
+ handle_ = dlopen(library, RTLD_NOW);
+ if (handle_ == NULL) {
+ ALOGE("Failed to dlopen %s: %s", library, dlerror());
+ return false;
+ }
+ if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetDefaultJavaVMInitArgs_),
+ "JNI_GetDefaultJavaVMInitArgs")) {
+ return false;
+ }
+ if (!FindSymbol(reinterpret_cast<void**>(&JNI_CreateJavaVM_),
+ "JNI_CreateJavaVM")) {
+ return false;
+ }
+ if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetCreatedJavaVMs_),
+ "JNI_GetCreatedJavaVMs")) {
+ return false;
+ }
+ return true;
+}
+
+jint JniInvocation::JNI_GetDefaultJavaVMInitArgs(void* vmargs) {
+ return JNI_GetDefaultJavaVMInitArgs_(vmargs);
+}
+
+jint JniInvocation::JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
+ return JNI_CreateJavaVM_(p_vm, p_env, vm_args);
+}
+
+jint JniInvocation::JNI_GetCreatedJavaVMs(JavaVM** vms, jsize size, jsize* vm_count) {
+ return JNI_GetCreatedJavaVMs_(vms, size, vm_count);
+}
+
+bool JniInvocation::FindSymbol(void** pointer, const char* symbol) {
+ *pointer = dlsym(handle_, symbol);
+ if (*pointer == NULL) {
+ ALOGE("Failed to find symbol %s: %s\n", symbol, dlerror());
+ dlclose(handle_);
+ handle_ = NULL;
+ return false;
+ }
+ return true;
+}
+
+JniInvocation& JniInvocation::GetJniInvocation() {
+ LOG_ALWAYS_FATAL_IF(jni_invocation_ == NULL,
+ "Failed to create JniInvocation instance before using JNI invocation API");
+ return *jni_invocation_;
+}
+
+extern "C" jint JNI_GetDefaultJavaVMInitArgs(void* vm_args) {
+ return JniInvocation::GetJniInvocation().JNI_GetDefaultJavaVMInitArgs(vm_args);
+}
+
+extern "C" jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
+ return JniInvocation::GetJniInvocation().JNI_CreateJavaVM(p_vm, p_env, vm_args);
+}
+
+extern "C" jint JNI_GetCreatedJavaVMs(JavaVM** vms, jsize size, jsize* vm_count) {
+ return JniInvocation::GetJniInvocation().JNI_GetCreatedJavaVMs(vms, size, vm_count);
+}
diff --git a/include/nativehelper/JniInvocation.h b/include/nativehelper/JniInvocation.h
new file mode 100644
index 0000000..603fdd2
--- /dev/null
+++ b/include/nativehelper/JniInvocation.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef JNI_INVOCATION_H_included
+#define JNI_INVOCATION_H_included
+
+#include <jni.h>
+
+// JniInvocation adds a layer of indirection for applications using
+// the JNI invocation API to allow the JNI implementation to be
+// selected dynamically. Apps can specify a specific implementation to
+// be used by calling InitJniInvocation. If this is not done, the
+// library will chosen based on the value of Android system property
+// dalvik.vm.lib on the device, and otherwise fall back to a hard-coded
+// default implementation.
+class JniInvocation {
+ public:
+ JniInvocation();
+
+ ~JniInvocation();
+
+ // Initialize JNI invocation API. library should specifiy a valid
+ // shared library for opening via dlopen providing a JNI invocation
+ // implementation, or null to allow defaulting via dalvik.vm.lib.
+ bool Init(const char* library);
+
+ private:
+
+ bool FindSymbol(void** pointer, const char* symbol);
+
+ static JniInvocation& GetJniInvocation();
+
+ jint JNI_GetDefaultJavaVMInitArgs(void* vmargs);
+ jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args);
+ jint JNI_GetCreatedJavaVMs(JavaVM** vms, jsize size, jsize* vm_count);
+
+ static JniInvocation* jni_invocation_;
+
+ void* handle_;
+ jint (*JNI_GetDefaultJavaVMInitArgs_)(void*);
+ jint (*JNI_CreateJavaVM_)(JavaVM**, JNIEnv**, void*);
+ jint (*JNI_GetCreatedJavaVMs_)(JavaVM**, jsize, jsize*);
+
+ friend jint JNI_GetDefaultJavaVMInitArgs(void* vm_args);
+ friend jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args);
+ friend jint JNI_GetCreatedJavaVMs(JavaVM** vms, jsize size, jsize* vm_count);
+};
+
+#endif // JNI_INVOCATION_H_included