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 HAVE_ANDROID_OS
     29 #include "cutils/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 HAVE_ANDROID_OS
     52 static const char* kLibrarySystemProperty = "persist.sys.dalvik.vm.lib";
     53 #endif
     54 static const char* kLibraryFallback = "libdvm.so";
     55 
     56 bool 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 
    103 jint JniInvocation::JNI_GetDefaultJavaVMInitArgs(void* vmargs) {
    104   return JNI_GetDefaultJavaVMInitArgs_(vmargs);
    105 }
    106 
    107 jint JniInvocation::JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
    108   return JNI_CreateJavaVM_(p_vm, p_env, vm_args);
    109 }
    110 
    111 jint JniInvocation::JNI_GetCreatedJavaVMs(JavaVM** vms, jsize size, jsize* vm_count) {
    112   return JNI_GetCreatedJavaVMs_(vms, size, vm_count);
    113 }
    114 
    115 bool 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 
    126 JniInvocation& 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 
    132 extern "C" jint JNI_GetDefaultJavaVMInitArgs(void* vm_args) {
    133   return JniInvocation::GetJniInvocation().JNI_GetDefaultJavaVMInitArgs(vm_args);
    134 }
    135 
    136 extern "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 
    140 extern "C" jint JNI_GetCreatedJavaVMs(JavaVM** vms, jsize size, jsize* vm_count) {
    141   return JniInvocation::GetJniInvocation().JNI_GetCreatedJavaVMs(vms, size, vm_count);
    142 }
    143