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 "JniInvocation.h" 18 19 #include <dlfcn.h> 20 #include <stdlib.h> 21 #include <string.h> 22 23 #include <cstddef> 24 25 #define LOG_TAG "JniInvocation" 26 #include "cutils/log.h" 27 28 #ifdef __ANDROID__ 29 #include <sys/system_properties.h> 30 #endif 31 32 JniInvocation* JniInvocation::jni_invocation_ = NULL; 33 34 JniInvocation::JniInvocation() : 35 handle_(NULL), 36 JNI_GetDefaultJavaVMInitArgs_(NULL), 37 JNI_CreateJavaVM_(NULL), 38 JNI_GetCreatedJavaVMs_(NULL) { 39 40 LOG_ALWAYS_FATAL_IF(jni_invocation_ != NULL, "JniInvocation instance already initialized"); 41 jni_invocation_ = this; 42 } 43 44 JniInvocation::~JniInvocation() { 45 jni_invocation_ = NULL; 46 if (handle_ != NULL) { 47 dlclose(handle_); 48 } 49 } 50 51 #ifdef __ANDROID__ 52 static const char* kLibrarySystemProperty = "persist.sys.dalvik.vm.lib.2"; 53 static const char* kDebuggableSystemProperty = "ro.debuggable"; 54 #endif 55 static const char* kLibraryFallback = "libart.so"; 56 57 template<typename T> void UNUSED(const T&) {} 58 59 const char* JniInvocation::GetLibrary(const char* library, char* buffer) { 60 #ifdef __ANDROID__ 61 const char* default_library; 62 63 char debuggable[PROP_VALUE_MAX]; 64 __system_property_get(kDebuggableSystemProperty, debuggable); 65 66 if (strcmp(debuggable, "1") != 0) { 67 // Not a debuggable build. 68 // Do not allow arbitrary library. Ignore the library parameter. This 69 // will also ignore the default library, but initialize to fallback 70 // for cleanliness. 71 library = kLibraryFallback; 72 default_library = kLibraryFallback; 73 } else { 74 // Debuggable build. 75 // Accept the library parameter. For the case it is NULL, load the default 76 // library from the system property. 77 if (buffer != NULL) { 78 if (__system_property_get(kLibrarySystemProperty, buffer) > 0) { 79 default_library = buffer; 80 } else { 81 default_library = kLibraryFallback; 82 } 83 } else { 84 // No buffer given, just use default fallback. 85 default_library = kLibraryFallback; 86 } 87 } 88 #else 89 UNUSED(buffer); 90 const char* default_library = kLibraryFallback; 91 #endif 92 if (library == NULL) { 93 library = default_library; 94 } 95 96 return library; 97 } 98 99 bool JniInvocation::Init(const char* library) { 100 #ifdef __ANDROID__ 101 char buffer[PROP_VALUE_MAX]; 102 #else 103 char* buffer = NULL; 104 #endif 105 library = GetLibrary(library, buffer); 106 // Load with RTLD_NODELETE in order to ensure that libart.so is not unmapped when it is closed. 107 // This is due to the fact that it is possible that some threads might have yet to finish 108 // exiting even after JNI_DeleteJavaVM returns, which can lead to segfaults if the library is 109 // unloaded. 110 const int kDlopenFlags = RTLD_NOW | RTLD_NODELETE; 111 handle_ = dlopen(library, kDlopenFlags); 112 if (handle_ == NULL) { 113 if (strcmp(library, kLibraryFallback) == 0) { 114 // Nothing else to try. 115 ALOGE("Failed to dlopen %s: %s", library, dlerror()); 116 return false; 117 } 118 // Note that this is enough to get something like the zygote 119 // running, we can't property_set here to fix this for the future 120 // because we are root and not the system user. See 121 // RuntimeInit.commonInit for where we fix up the property to 122 // avoid future fallbacks. http://b/11463182 123 ALOGW("Falling back from %s to %s after dlopen error: %s", 124 library, kLibraryFallback, dlerror()); 125 library = kLibraryFallback; 126 handle_ = dlopen(library, kDlopenFlags); 127 if (handle_ == NULL) { 128 ALOGE("Failed to dlopen %s: %s", library, dlerror()); 129 return false; 130 } 131 } 132 if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetDefaultJavaVMInitArgs_), 133 "JNI_GetDefaultJavaVMInitArgs")) { 134 return false; 135 } 136 if (!FindSymbol(reinterpret_cast<void**>(&JNI_CreateJavaVM_), 137 "JNI_CreateJavaVM")) { 138 return false; 139 } 140 if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetCreatedJavaVMs_), 141 "JNI_GetCreatedJavaVMs")) { 142 return false; 143 } 144 return true; 145 } 146 147 jint JniInvocation::JNI_GetDefaultJavaVMInitArgs(void* vmargs) { 148 return JNI_GetDefaultJavaVMInitArgs_(vmargs); 149 } 150 151 jint JniInvocation::JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) { 152 return JNI_CreateJavaVM_(p_vm, p_env, vm_args); 153 } 154 155 jint JniInvocation::JNI_GetCreatedJavaVMs(JavaVM** vms, jsize size, jsize* vm_count) { 156 return JNI_GetCreatedJavaVMs_(vms, size, vm_count); 157 } 158 159 bool JniInvocation::FindSymbol(void** pointer, const char* symbol) { 160 *pointer = dlsym(handle_, symbol); 161 if (*pointer == NULL) { 162 ALOGE("Failed to find symbol %s: %s\n", symbol, dlerror()); 163 dlclose(handle_); 164 handle_ = NULL; 165 return false; 166 } 167 return true; 168 } 169 170 JniInvocation& JniInvocation::GetJniInvocation() { 171 LOG_ALWAYS_FATAL_IF(jni_invocation_ == NULL, 172 "Failed to create JniInvocation instance before using JNI invocation API"); 173 return *jni_invocation_; 174 } 175 176 extern "C" jint JNI_GetDefaultJavaVMInitArgs(void* vm_args) { 177 return JniInvocation::GetJniInvocation().JNI_GetDefaultJavaVMInitArgs(vm_args); 178 } 179 180 extern "C" jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) { 181 return JniInvocation::GetJniInvocation().JNI_CreateJavaVM(p_vm, p_env, vm_args); 182 } 183 184 extern "C" jint JNI_GetCreatedJavaVMs(JavaVM** vms, jsize size, jsize* vm_count) { 185 return JniInvocation::GetJniInvocation().JNI_GetCreatedJavaVMs(vms, size, vm_count); 186 } 187