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 <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