Home | History | Annotate | Download | only in libnativehelper
      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