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 <string> 20 21 #ifdef _WIN32 22 #include <windows.h> 23 #else 24 #include <dlfcn.h> 25 #endif 26 27 #define LOG_TAG "JniInvocation" 28 #include <log/log.h> 29 30 #if defined(__ANDROID__) 31 #include <sys/system_properties.h> 32 #elif defined(_WIN32) 33 #include <android-base/errors.h> 34 #endif 35 36 #include "JniConstants.h" 37 38 namespace { 39 40 template <typename T> 41 void UNUSED(const T&) {} 42 43 bool IsDebuggable() { 44 #ifdef __ANDROID__ 45 char debuggable[PROP_VALUE_MAX] = {0}; 46 __system_property_get("ro.debuggable", debuggable); 47 return strcmp(debuggable, "1") == 0; 48 #else 49 return false; 50 #endif 51 } 52 53 int GetLibrarySystemProperty(char* buffer) { 54 #ifdef __ANDROID__ 55 return __system_property_get("persist.sys.dalvik.vm.lib.2", buffer); 56 #else 57 UNUSED(buffer); 58 return 0; 59 #endif 60 } 61 62 #ifdef _WIN32 63 #define FUNC_POINTER FARPROC 64 #else 65 #define FUNC_POINTER void* 66 #endif 67 68 void* OpenLibrary(const char* filename) { 69 #ifdef _WIN32 70 return LoadLibrary(filename); 71 #else 72 // Load with RTLD_NODELETE in order to ensure that libart.so is not unmapped when it is closed. 73 // This is due to the fact that it is possible that some threads might have yet to finish 74 // exiting even after JNI_DeleteJavaVM returns, which can lead to segfaults if the library is 75 // unloaded. 76 const int kDlopenFlags = RTLD_NOW | RTLD_NODELETE; 77 return dlopen(filename, kDlopenFlags); 78 #endif 79 } 80 81 int CloseLibrary(void* handle) { 82 #ifdef _WIN32 83 return FreeLibrary(static_cast<HMODULE>(handle)); 84 #else 85 return dlclose(handle); 86 #endif 87 } 88 89 FUNC_POINTER GetSymbol(void* handle, const char* symbol) { 90 #ifdef _WIN32 91 return GetProcAddress(static_cast<HMODULE>(handle), symbol); 92 #else 93 return dlsym(handle, symbol); 94 #endif 95 } 96 97 std::string GetError() { 98 #ifdef _WIN32 99 return android::base::SystemErrorCodeToString(GetLastError()); 100 #else 101 return std::string(dlerror()); 102 #endif 103 } 104 105 } // namespace 106 107 struct JniInvocationImpl final { 108 public: 109 JniInvocationImpl(); 110 ~JniInvocationImpl(); 111 112 bool Init(const char* library); 113 114 static const char* GetLibrary(const char* library, 115 char* buffer, 116 bool (*is_debuggable)() = IsDebuggable, 117 int (*get_library_system_property)(char* buffer) = GetLibrarySystemProperty); 118 119 static JniInvocationImpl& GetJniInvocation(); 120 121 jint JNI_GetDefaultJavaVMInitArgs(void* vmargs); 122 jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args); 123 jint JNI_GetCreatedJavaVMs(JavaVM** vms, jsize size, jsize* vm_count); 124 125 private: 126 JniInvocationImpl(const JniInvocationImpl&) = delete; 127 JniInvocationImpl& operator=(const JniInvocationImpl&) = delete; 128 129 bool FindSymbol(FUNC_POINTER* pointer, const char* symbol); 130 131 static JniInvocationImpl* jni_invocation_; 132 133 // Handle to library opened with dlopen(). Library exports 134 // JNI_GetDefaultJavaVMInitArgs, JNI_CreateJavaVM, JNI_GetCreatedJavaVMs. 135 void* handle_; 136 jint (*JNI_GetDefaultJavaVMInitArgs_)(void*); 137 jint (*JNI_CreateJavaVM_)(JavaVM**, JNIEnv**, void*); 138 jint (*JNI_GetCreatedJavaVMs_)(JavaVM**, jsize, jsize*); 139 140 friend class JNIInvocation_Debuggable_Test; 141 friend class JNIInvocation_NonDebuggable_Test; 142 }; 143 144 // Check JniInvocationImpl size is same as fields, e.g. no vtable present. 145 static_assert(sizeof(JniInvocationImpl) == 4 * sizeof(uintptr_t)); 146 147 JniInvocationImpl* JniInvocationImpl::jni_invocation_ = NULL; 148 149 JniInvocationImpl::JniInvocationImpl() : 150 handle_(NULL), 151 JNI_GetDefaultJavaVMInitArgs_(NULL), 152 JNI_CreateJavaVM_(NULL), 153 JNI_GetCreatedJavaVMs_(NULL) { 154 LOG_ALWAYS_FATAL_IF(jni_invocation_ != NULL, "JniInvocation instance already initialized"); 155 jni_invocation_ = this; 156 } 157 158 JniInvocationImpl::~JniInvocationImpl() { 159 jni_invocation_ = NULL; 160 if (handle_ != NULL) { 161 CloseLibrary(handle_); 162 } 163 } 164 165 static const char* kLibraryFallback = "libart.so"; 166 167 const char* JniInvocationImpl::GetLibrary(const char* library, 168 char* buffer, 169 bool (*is_debuggable)(), 170 int (*get_library_system_property)(char* buffer)) { 171 #ifdef __ANDROID__ 172 const char* default_library; 173 174 if (!is_debuggable()) { 175 // Not a debuggable build. 176 // Do not allow arbitrary library. Ignore the library parameter. This 177 // will also ignore the default library, but initialize to fallback 178 // for cleanliness. 179 library = kLibraryFallback; 180 default_library = kLibraryFallback; 181 } else { 182 // Debuggable build. 183 // Accept the library parameter. For the case it is NULL, load the default 184 // library from the system property. 185 if (buffer != NULL) { 186 if (get_library_system_property(buffer) > 0) { 187 default_library = buffer; 188 } else { 189 default_library = kLibraryFallback; 190 } 191 } else { 192 // No buffer given, just use default fallback. 193 default_library = kLibraryFallback; 194 } 195 } 196 #else 197 UNUSED(buffer); 198 UNUSED(is_debuggable); 199 UNUSED(get_library_system_property); 200 const char* default_library = kLibraryFallback; 201 #endif 202 if (library == NULL) { 203 library = default_library; 204 } 205 206 return library; 207 } 208 209 bool JniInvocationImpl::Init(const char* library) { 210 #ifdef __ANDROID__ 211 char buffer[PROP_VALUE_MAX]; 212 #else 213 char* buffer = NULL; 214 #endif 215 library = GetLibrary(library, buffer); 216 handle_ = OpenLibrary(library); 217 if (handle_ == NULL) { 218 if (strcmp(library, kLibraryFallback) == 0) { 219 // Nothing else to try. 220 ALOGE("Failed to dlopen %s: %s", library, GetError().c_str()); 221 return false; 222 } 223 // Note that this is enough to get something like the zygote 224 // running, we can't property_set here to fix this for the future 225 // because we are root and not the system user. See 226 // RuntimeInit.commonInit for where we fix up the property to 227 // avoid future fallbacks. http://b/11463182 228 ALOGW("Falling back from %s to %s after dlopen error: %s", 229 library, kLibraryFallback, GetError().c_str()); 230 library = kLibraryFallback; 231 handle_ = OpenLibrary(library); 232 if (handle_ == NULL) { 233 ALOGE("Failed to dlopen %s: %s", library, GetError().c_str()); 234 return false; 235 } 236 } 237 if (!FindSymbol(reinterpret_cast<FUNC_POINTER*>(&JNI_GetDefaultJavaVMInitArgs_), 238 "JNI_GetDefaultJavaVMInitArgs")) { 239 return false; 240 } 241 if (!FindSymbol(reinterpret_cast<FUNC_POINTER*>(&JNI_CreateJavaVM_), 242 "JNI_CreateJavaVM")) { 243 return false; 244 } 245 if (!FindSymbol(reinterpret_cast<FUNC_POINTER*>(&JNI_GetCreatedJavaVMs_), 246 "JNI_GetCreatedJavaVMs")) { 247 return false; 248 } 249 return true; 250 } 251 252 jint JniInvocationImpl::JNI_GetDefaultJavaVMInitArgs(void* vmargs) { 253 return JNI_GetDefaultJavaVMInitArgs_(vmargs); 254 } 255 256 jint JniInvocationImpl::JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) { 257 return JNI_CreateJavaVM_(p_vm, p_env, vm_args); 258 } 259 260 jint JniInvocationImpl::JNI_GetCreatedJavaVMs(JavaVM** vms, jsize size, jsize* vm_count) { 261 return JNI_GetCreatedJavaVMs_(vms, size, vm_count); 262 } 263 264 bool JniInvocationImpl::FindSymbol(FUNC_POINTER* pointer, const char* symbol) { 265 *pointer = GetSymbol(handle_, symbol); 266 if (*pointer == NULL) { 267 ALOGE("Failed to find symbol %s: %s\n", symbol, GetError().c_str()); 268 CloseLibrary(handle_); 269 handle_ = NULL; 270 return false; 271 } 272 return true; 273 } 274 275 JniInvocationImpl& JniInvocationImpl::GetJniInvocation() { 276 LOG_ALWAYS_FATAL_IF(jni_invocation_ == NULL, 277 "Failed to create JniInvocation instance before using JNI invocation API"); 278 return *jni_invocation_; 279 } 280 281 jint JNI_GetDefaultJavaVMInitArgs(void* vm_args) { 282 return JniInvocationImpl::GetJniInvocation().JNI_GetDefaultJavaVMInitArgs(vm_args); 283 } 284 285 jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) { 286 // Ensure any cached heap objects from previous VM instances are 287 // invalidated. There is no notification here that a VM is destroyed. These 288 // cached objects limit us to one VM instance per process. 289 JniConstants::Uninitialize(); 290 return JniInvocationImpl::GetJniInvocation().JNI_CreateJavaVM(p_vm, p_env, vm_args); 291 } 292 293 jint JNI_GetCreatedJavaVMs(JavaVM** vms, jsize size, jsize* vm_count) { 294 return JniInvocationImpl::GetJniInvocation().JNI_GetCreatedJavaVMs(vms, size, vm_count); 295 } 296 297 const char* JniInvocation::GetLibrary(const char* library, 298 char* buffer, 299 bool (*is_debuggable)(), 300 int (*get_library_system_property)(char* buffer)) { 301 return JniInvocationImpl::GetLibrary(library, buffer, is_debuggable, get_library_system_property); 302 } 303 304 JniInvocationImpl* JniInvocationCreate() { 305 return new JniInvocationImpl(); 306 } 307 308 void JniInvocationDestroy(JniInvocationImpl* instance) { 309 delete instance; 310 } 311 312 int JniInvocationInit(JniInvocationImpl* instance, const char* library) { 313 return instance->Init(library) ? 1 : 0; 314 } 315 316 const char* JniInvocationGetLibrary(const char* library, char* buffer) { 317 return JniInvocationImpl::GetLibrary(library, buffer); 318 } 319