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