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 HAVE_ANDROID_OS 29#include "cutils/properties.h" 30#endif 31 32JniInvocation* JniInvocation::jni_invocation_ = NULL; 33 34JniInvocation::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 44JniInvocation::~JniInvocation() { 45 jni_invocation_ = NULL; 46 if (handle_ != NULL) { 47 dlclose(handle_); 48 } 49} 50 51#ifdef HAVE_ANDROID_OS 52static const char* kLibrarySystemProperty = "persist.sys.dalvik.vm.lib"; 53#endif 54static const char* kLibraryFallback = "libdvm.so"; 55 56bool JniInvocation::Init(const char* library) { 57#ifdef HAVE_ANDROID_OS 58 char default_library[PROPERTY_VALUE_MAX]; 59 property_get(kLibrarySystemProperty, default_library, kLibraryFallback); 60#else 61 const char* default_library = kLibraryFallback; 62#endif 63 if (library == NULL) { 64 library = default_library; 65 } 66 67 handle_ = dlopen(library, RTLD_NOW); 68 if (handle_ == NULL) { 69 if (strcmp(library, kLibraryFallback) == 0) { 70 // Nothing else to try. 71 ALOGE("Failed to dlopen %s: %s", library, dlerror()); 72 return false; 73 } 74 // Note that this is enough to get something like the zygote 75 // running, we can't property_set here to fix this for the future 76 // because we are root and not the system user. See 77 // RuntimeInit.commonInit for where we fix up the property to 78 // avoid future fallbacks. http://b/11463182 79 ALOGW("Falling back from %s to %s after dlopen error: %s", 80 library, kLibraryFallback, dlerror()); 81 library = kLibraryFallback; 82 handle_ = dlopen(library, RTLD_NOW); 83 if (handle_ == NULL) { 84 ALOGE("Failed to dlopen %s: %s", library, dlerror()); 85 return false; 86 } 87 } 88 if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetDefaultJavaVMInitArgs_), 89 "JNI_GetDefaultJavaVMInitArgs")) { 90 return false; 91 } 92 if (!FindSymbol(reinterpret_cast<void**>(&JNI_CreateJavaVM_), 93 "JNI_CreateJavaVM")) { 94 return false; 95 } 96 if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetCreatedJavaVMs_), 97 "JNI_GetCreatedJavaVMs")) { 98 return false; 99 } 100 return true; 101} 102 103jint JniInvocation::JNI_GetDefaultJavaVMInitArgs(void* vmargs) { 104 return JNI_GetDefaultJavaVMInitArgs_(vmargs); 105} 106 107jint JniInvocation::JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) { 108 return JNI_CreateJavaVM_(p_vm, p_env, vm_args); 109} 110 111jint JniInvocation::JNI_GetCreatedJavaVMs(JavaVM** vms, jsize size, jsize* vm_count) { 112 return JNI_GetCreatedJavaVMs_(vms, size, vm_count); 113} 114 115bool JniInvocation::FindSymbol(void** pointer, const char* symbol) { 116 *pointer = dlsym(handle_, symbol); 117 if (*pointer == NULL) { 118 ALOGE("Failed to find symbol %s: %s\n", symbol, dlerror()); 119 dlclose(handle_); 120 handle_ = NULL; 121 return false; 122 } 123 return true; 124} 125 126JniInvocation& JniInvocation::GetJniInvocation() { 127 LOG_ALWAYS_FATAL_IF(jni_invocation_ == NULL, 128 "Failed to create JniInvocation instance before using JNI invocation API"); 129 return *jni_invocation_; 130} 131 132extern "C" jint JNI_GetDefaultJavaVMInitArgs(void* vm_args) { 133 return JniInvocation::GetJniInvocation().JNI_GetDefaultJavaVMInitArgs(vm_args); 134} 135 136extern "C" jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) { 137 return JniInvocation::GetJniInvocation().JNI_CreateJavaVM(p_vm, p_env, vm_args); 138} 139 140extern "C" jint JNI_GetCreatedJavaVMs(JavaVM** vms, jsize size, jsize* vm_count) { 141 return JniInvocation::GetJniInvocation().JNI_GetCreatedJavaVMs(vms, size, vm_count); 142} 143