• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
JniInvocation()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 
~JniInvocation()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 
UNUSED(const T &)57 template<typename T> void UNUSED(const T&) {}
58 
GetLibrary(const char * library,char * buffer)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 
Init(const char * library)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 
JNI_GetDefaultJavaVMInitArgs(void * vmargs)147 jint JniInvocation::JNI_GetDefaultJavaVMInitArgs(void* vmargs) {
148   return JNI_GetDefaultJavaVMInitArgs_(vmargs);
149 }
150 
JNI_CreateJavaVM(JavaVM ** p_vm,JNIEnv ** p_env,void * vm_args)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 
JNI_GetCreatedJavaVMs(JavaVM ** vms,jsize size,jsize * vm_count)155 jint JniInvocation::JNI_GetCreatedJavaVMs(JavaVM** vms, jsize size, jsize* vm_count) {
156   return JNI_GetCreatedJavaVMs_(vms, size, vm_count);
157 }
158 
FindSymbol(void ** pointer,const char * symbol)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 
GetJniInvocation()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 
JNI_GetDefaultJavaVMInitArgs(void * vm_args)176 extern "C" jint JNI_GetDefaultJavaVMInitArgs(void* vm_args) {
177   return JniInvocation::GetJniInvocation().JNI_GetDefaultJavaVMInitArgs(vm_args);
178 }
179 
JNI_CreateJavaVM(JavaVM ** p_vm,JNIEnv ** p_env,void * vm_args)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 
JNI_GetCreatedJavaVMs(JavaVM ** vms,jsize size,jsize * vm_count)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