1 /* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "include_platform/nativehelper/JniInvocation.h" 18 19 #define LOG_TAG "JniInvocation" 20 #include "ALog-priv.h" 21 22 #if defined(__ANDROID__) 23 #include <sys/system_properties.h> 24 #endif 25 26 #include <jni.h> 27 #include <stdbool.h> 28 #include <string.h> 29 30 #include "DlHelp.h" 31 32 // Name the default library providing the JNI Invocation API. 33 static const char* kDefaultJniInvocationLibrary = "libart.so"; 34 35 struct JniInvocationImpl { 36 // Name of library providing JNI_ method implementations. 37 const char* jni_provider_library_name; 38 39 // Opaque pointer to shared library from dlopen / LoadLibrary. 40 void* jni_provider_library; 41 42 // Function pointers to methods in JNI provider. 43 jint (*JNI_GetDefaultJavaVMInitArgs)(void*); 44 jint (*JNI_CreateJavaVM)(JavaVM**, JNIEnv**, void*); 45 jint (*JNI_GetCreatedJavaVMs)(JavaVM**, jsize, jsize*); 46 }; 47 48 static struct JniInvocationImpl g_impl; 49 50 // 51 // Internal helpers. 52 // 53 54 #define UNUSED(x) (x) = (x) 55 56 static bool IsDebuggable() { 57 #ifdef __ANDROID__ 58 char debuggable[PROP_VALUE_MAX] = {0}; 59 __system_property_get("ro.debuggable", debuggable); 60 return strcmp(debuggable, "1") == 0; 61 #else 62 // Host is always treated as debuggable, which allows choice of library to be overridden. 63 return true; 64 #endif 65 } 66 67 static int GetLibrarySystemProperty(char* buffer) { 68 #ifdef __ANDROID__ 69 return __system_property_get("persist.sys.dalvik.vm.lib.2", buffer); 70 #else 71 // Host does not use properties. 72 UNUSED(buffer); 73 return 0; 74 #endif 75 } 76 77 static DlSymbol FindSymbol(DlLibrary library, const char* symbol) { 78 DlSymbol s = DlGetSymbol(library, symbol); 79 if (s == NULL) { 80 ALOGE("Failed to find symbol: %s", symbol); 81 } 82 return s; 83 } 84 85 // 86 // Exported functions for JNI based VM management from JNI spec. 87 // 88 89 jint JNI_GetDefaultJavaVMInitArgs(void* vmargs) { 90 ALOG_ALWAYS_FATAL_IF(NULL == g_impl.JNI_GetDefaultJavaVMInitArgs, "Runtime library not loaded."); 91 return g_impl.JNI_GetDefaultJavaVMInitArgs(vmargs); 92 } 93 94 jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) { 95 ALOG_ALWAYS_FATAL_IF(NULL == g_impl.JNI_CreateJavaVM, "Runtime library not loaded."); 96 return g_impl.JNI_CreateJavaVM(p_vm, p_env, vm_args); 97 } 98 99 jint JNI_GetCreatedJavaVMs(JavaVM** vms, jsize size, jsize* vm_count) { 100 if (NULL == g_impl.JNI_GetCreatedJavaVMs) { 101 *vm_count = 0; 102 return JNI_OK; 103 } 104 return g_impl.JNI_GetCreatedJavaVMs(vms, size, vm_count); 105 } 106 107 // 108 // JniInvocation functions for setting up JNI functions. 109 // 110 111 const char* JniInvocationGetLibraryWith(const char* library, 112 bool is_debuggable, 113 const char* system_preferred_library) { 114 if (is_debuggable) { 115 // Debuggable property is set. Allow library providing JNI Invocation API to be overridden. 116 117 // Choose the library parameter (if provided). 118 if (library != NULL) { 119 return library; 120 } 121 // Choose the system_preferred_library (if provided). 122 if (system_preferred_library != NULL) { 123 return system_preferred_library; 124 } 125 } 126 return kDefaultJniInvocationLibrary; 127 } 128 129 const char* JniInvocationGetLibrary(const char* library, char* buffer) { 130 bool debuggable = IsDebuggable(); 131 const char* system_preferred_library = NULL; 132 if (buffer != NULL && (GetLibrarySystemProperty(buffer) > 0)) { 133 system_preferred_library = buffer; 134 } 135 return JniInvocationGetLibraryWith(library, debuggable, system_preferred_library); 136 } 137 138 struct JniInvocationImpl* JniInvocationCreate() { 139 // Android only supports a single JniInvocation instance and only a single JavaVM. 140 if (g_impl.jni_provider_library != NULL) { 141 return NULL; 142 } 143 return &g_impl; 144 } 145 146 bool JniInvocationInit(struct JniInvocationImpl* instance, const char* library_name) { 147 #ifdef __ANDROID__ 148 char buffer[PROP_VALUE_MAX]; 149 #else 150 char* buffer = NULL; 151 #endif 152 library_name = JniInvocationGetLibrary(library_name, buffer); 153 DlLibrary library = DlOpenLibrary(library_name); 154 if (library == NULL) { 155 if (strcmp(library_name, kDefaultJniInvocationLibrary) == 0) { 156 // Nothing else to try. 157 ALOGE("Failed to dlopen %s: %s", library_name, DlGetError()); 158 return false; 159 } 160 // Note that this is enough to get something like the zygote 161 // running, we can't property_set here to fix this for the future 162 // because we are root and not the system user. See 163 // RuntimeInit.commonInit for where we fix up the property to 164 // avoid future fallbacks. http://b/11463182 165 ALOGW("Falling back from %s to %s after dlopen error: %s", 166 library_name, kDefaultJniInvocationLibrary, DlGetError()); 167 library_name = kDefaultJniInvocationLibrary; 168 library = DlOpenLibrary(library_name); 169 if (library == NULL) { 170 ALOGE("Failed to dlopen %s: %s", library_name, DlGetError()); 171 return false; 172 } 173 } 174 175 DlSymbol JNI_GetDefaultJavaVMInitArgs_ = FindSymbol(library, "JNI_GetDefaultJavaVMInitArgs"); 176 if (JNI_GetDefaultJavaVMInitArgs_ == NULL) { 177 return false; 178 } 179 180 DlSymbol JNI_CreateJavaVM_ = FindSymbol(library, "JNI_CreateJavaVM"); 181 if (JNI_CreateJavaVM_ == NULL) { 182 return false; 183 } 184 185 DlSymbol JNI_GetCreatedJavaVMs_ = FindSymbol(library, "JNI_GetCreatedJavaVMs"); 186 if (JNI_GetCreatedJavaVMs_ == NULL) { 187 return false; 188 } 189 190 instance->jni_provider_library_name = library_name; 191 instance->jni_provider_library = library; 192 instance->JNI_GetDefaultJavaVMInitArgs = (jint (*)(void *)) JNI_GetDefaultJavaVMInitArgs_; 193 instance->JNI_CreateJavaVM = (jint (*)(JavaVM**, JNIEnv**, void*)) JNI_CreateJavaVM_; 194 instance->JNI_GetCreatedJavaVMs = (jint (*)(JavaVM**, jsize, jsize*)) JNI_GetCreatedJavaVMs_; 195 196 return true; 197 } 198 199 void JniInvocationDestroy(struct JniInvocationImpl* instance) { 200 DlCloseLibrary(instance->jni_provider_library); 201 memset(instance, 0, sizeof(*instance)); 202 } 203