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>
UNUSED(const T &)33 void UNUSED(const T&) {}
34 
IsDebuggable()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 
GetLibrarySystemProperty(char * buffer)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 
JniInvocation()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 
~JniInvocation()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 
GetLibrary(const char * library,char * buffer)75 const char* JniInvocation::GetLibrary(const char* library, char* buffer) {
76   return GetLibrary(library, buffer, &IsDebuggable, &GetLibrarySystemProperty);
77 }
78 
GetLibrary(const char * library,char * buffer,bool (* is_debuggable)(),int (* get_library_system_property)(char * buffer))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 
Init(const char * library)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 
JNI_GetDefaultJavaVMInitArgs(void * vmargs)167 jint JniInvocation::JNI_GetDefaultJavaVMInitArgs(void* vmargs) {
168   return JNI_GetDefaultJavaVMInitArgs_(vmargs);
169 }
170 
JNI_CreateJavaVM(JavaVM ** p_vm,JNIEnv ** p_env,void * vm_args)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 
JNI_GetCreatedJavaVMs(JavaVM ** vms,jsize size,jsize * vm_count)175 jint JniInvocation::JNI_GetCreatedJavaVMs(JavaVM** vms, jsize size, jsize* vm_count) {
176   return JNI_GetCreatedJavaVMs_(vms, size, vm_count);
177 }
178 
FindSymbol(void ** pointer,const char * symbol)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 
GetJniInvocation()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 
JNI_GetDefaultJavaVMInitArgs(void * vm_args)196 extern "C" jint JNI_GetDefaultJavaVMInitArgs(void* vm_args) {
197   return JniInvocation::GetJniInvocation().JNI_GetDefaultJavaVMInitArgs(vm_args);
198 }
199 
JNI_CreateJavaVM(JavaVM ** p_vm,JNIEnv ** p_env,void * vm_args)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 
JNI_GetCreatedJavaVMs(JavaVM ** vms,jsize size,jsize * vm_count)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