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 #ifdef _WIN32
20 #include <windows.h>
21 #else
22 #include <dlfcn.h>
23 #endif
24 #include <stdlib.h>
25 #include <string.h>
26 
27 #include <cstddef>
28 
29 #define LOG_TAG "JniInvocation"
30 #include <log/log.h>
31 
32 #ifdef __ANDROID__
33 #include <sys/system_properties.h>
34 #endif
35 
36 #include "android-base/errors.h"
37 #include "JniConstants.h"
38 
39 namespace {
40 
41 template <typename T>
UNUSED(const T &)42 void UNUSED(const T&) {}
43 
IsDebuggable()44 bool IsDebuggable() {
45 #ifdef __ANDROID__
46   char debuggable[PROP_VALUE_MAX] = {0};
47   __system_property_get("ro.debuggable", debuggable);
48   return strcmp(debuggable, "1") == 0;
49 #else
50   return false;
51 #endif
52 }
53 
GetLibrarySystemProperty(char * buffer)54 int GetLibrarySystemProperty(char* buffer) {
55 #ifdef __ANDROID__
56   return __system_property_get("persist.sys.dalvik.vm.lib.2", buffer);
57 #else
58   UNUSED(buffer);
59   return 0;
60 #endif
61 }
62 
63 #ifdef _WIN32
64 #define FUNC_POINTER FARPROC
65 #else
66 #define FUNC_POINTER void*
67 #endif
68 
OpenLibrary(const char * filename)69 void* OpenLibrary(const char* filename) {
70 #ifdef _WIN32
71   return LoadLibrary(filename);
72 #else
73   // Load with RTLD_NODELETE in order to ensure that libart.so is not unmapped when it is closed.
74   // This is due to the fact that it is possible that some threads might have yet to finish
75   // exiting even after JNI_DeleteJavaVM returns, which can lead to segfaults if the library is
76   // unloaded.
77   const int kDlopenFlags = RTLD_NOW | RTLD_NODELETE;
78   return dlopen(filename, kDlopenFlags);
79 #endif
80 }
81 
CloseLibrary(void * handle)82 int CloseLibrary(void* handle) {
83 #ifdef _WIN32
84   return FreeLibrary(static_cast<HMODULE>(handle));
85 #else
86   return dlclose(handle);
87 #endif
88 }
89 
GetSymbol(void * handle,const char * symbol)90 FUNC_POINTER GetSymbol(void* handle, const char* symbol) {
91 #ifdef _WIN32
92   return GetProcAddress(static_cast<HMODULE>(handle), symbol);
93 #else
94   return dlsym(handle, symbol);
95 #endif
96 }
97 
GetError()98 std::string GetError() {
99 #ifdef _WIN32
100   return android::base::SystemErrorCodeToString(GetLastError());
101 #else
102   return std::string(dlerror());
103 #endif
104 }
105 
106 }  // namespace
107 
108 struct JniInvocationImpl final {
109  public:
110   JniInvocationImpl();
111   ~JniInvocationImpl();
112 
113   bool Init(const char* library);
114 
115   //  static const char* GetLibrary(const char* library, char* buffer);
116 
117   static const char* GetLibrary(const char* library,
118                                 char* buffer,
119                                 bool (*is_debuggable)() = IsDebuggable,
120                                 int (*get_library_system_property)(char* buffer) = GetLibrarySystemProperty);
121 
122   static JniInvocationImpl& GetJniInvocation();
123 
124   jint JNI_GetDefaultJavaVMInitArgs(void* vmargs);
125   jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args);
126   jint JNI_GetCreatedJavaVMs(JavaVM** vms, jsize size, jsize* vm_count);
127 
128  private:
129   JniInvocationImpl(const JniInvocationImpl&) = delete;
130   JniInvocationImpl& operator=(const JniInvocationImpl&) = delete;
131 
132   bool FindSymbol(FUNC_POINTER* pointer, const char* symbol);
133 
134   static JniInvocationImpl* jni_invocation_;
135 
136   // Handle to library opened with dlopen(). Library exports
137   // JNI_GetDefaultJavaVMInitArgs, JNI_CreateJavaVM, JNI_GetCreatedJavaVMs.
138   void* handle_;
139   jint (*JNI_GetDefaultJavaVMInitArgs_)(void*);
140   jint (*JNI_CreateJavaVM_)(JavaVM**, JNIEnv**, void*);
141   jint (*JNI_GetCreatedJavaVMs_)(JavaVM**, jsize, jsize*);
142 
143   friend class JNIInvocation_Debuggable_Test;
144   friend class JNIInvocation_NonDebuggable_Test;
145 };
146 
147 // Check JniInvocationImpl size is same as fields, e.g. no vtable present.
148 static_assert(sizeof(JniInvocationImpl) == 4 * sizeof(uintptr_t));
149 
150 JniInvocationImpl* JniInvocationImpl::jni_invocation_ = NULL;
151 
JniInvocationImpl()152 JniInvocationImpl::JniInvocationImpl() :
153     handle_(NULL),
154     JNI_GetDefaultJavaVMInitArgs_(NULL),
155     JNI_CreateJavaVM_(NULL),
156     JNI_GetCreatedJavaVMs_(NULL) {
157   LOG_ALWAYS_FATAL_IF(jni_invocation_ != NULL, "JniInvocation instance already initialized");
158   jni_invocation_ = this;
159 }
160 
~JniInvocationImpl()161 JniInvocationImpl::~JniInvocationImpl() {
162   jni_invocation_ = NULL;
163   if (handle_ != NULL) {
164     CloseLibrary(handle_);
165   }
166 }
167 
168 static const char* kLibraryFallback = "libart.so";
169 
GetLibrary(const char * library,char * buffer,bool (* is_debuggable)(),int (* get_library_system_property)(char * buffer))170 const char* JniInvocationImpl::GetLibrary(const char* library,
171                                           char* buffer,
172                                           bool (*is_debuggable)(),
173                                           int (*get_library_system_property)(char* buffer)) {
174 #ifdef __ANDROID__
175   const char* default_library;
176 
177   if (!is_debuggable()) {
178     // Not a debuggable build.
179     // Do not allow arbitrary library. Ignore the library parameter. This
180     // will also ignore the default library, but initialize to fallback
181     // for cleanliness.
182     library = kLibraryFallback;
183     default_library = kLibraryFallback;
184   } else {
185     // Debuggable build.
186     // Accept the library parameter. For the case it is NULL, load the default
187     // library from the system property.
188     if (buffer != NULL) {
189       if (get_library_system_property(buffer) > 0) {
190         default_library = buffer;
191       } else {
192         default_library = kLibraryFallback;
193       }
194     } else {
195       // No buffer given, just use default fallback.
196       default_library = kLibraryFallback;
197     }
198   }
199 #else
200   UNUSED(buffer);
201   UNUSED(is_debuggable);
202   UNUSED(get_library_system_property);
203   const char* default_library = kLibraryFallback;
204 #endif
205   if (library == NULL) {
206     library = default_library;
207   }
208 
209   return library;
210 }
211 
Init(const char * library)212 bool JniInvocationImpl::Init(const char* library) {
213 #ifdef __ANDROID__
214   char buffer[PROP_VALUE_MAX];
215 #else
216   char* buffer = NULL;
217 #endif
218   library = GetLibrary(library, buffer);
219   handle_ = OpenLibrary(library);
220   if (handle_ == NULL) {
221     if (strcmp(library, kLibraryFallback) == 0) {
222       // Nothing else to try.
223       ALOGE("Failed to dlopen %s: %s", library, GetError().c_str());
224       return false;
225     }
226     // Note that this is enough to get something like the zygote
227     // running, we can't property_set here to fix this for the future
228     // because we are root and not the system user. See
229     // RuntimeInit.commonInit for where we fix up the property to
230     // avoid future fallbacks. http://b/11463182
231     ALOGW("Falling back from %s to %s after dlopen error: %s",
232           library, kLibraryFallback, GetError().c_str());
233     library = kLibraryFallback;
234     handle_ = OpenLibrary(library);
235     if (handle_ == NULL) {
236       ALOGE("Failed to dlopen %s: %s", library, GetError().c_str());
237       return false;
238     }
239   }
240   if (!FindSymbol(reinterpret_cast<FUNC_POINTER*>(&JNI_GetDefaultJavaVMInitArgs_),
241                   "JNI_GetDefaultJavaVMInitArgs")) {
242     return false;
243   }
244   if (!FindSymbol(reinterpret_cast<FUNC_POINTER*>(&JNI_CreateJavaVM_),
245                   "JNI_CreateJavaVM")) {
246     return false;
247   }
248   if (!FindSymbol(reinterpret_cast<FUNC_POINTER*>(&JNI_GetCreatedJavaVMs_),
249                   "JNI_GetCreatedJavaVMs")) {
250     return false;
251   }
252   return true;
253 }
254 
JNI_GetDefaultJavaVMInitArgs(void * vmargs)255 jint JniInvocationImpl::JNI_GetDefaultJavaVMInitArgs(void* vmargs) {
256   return JNI_GetDefaultJavaVMInitArgs_(vmargs);
257 }
258 
JNI_CreateJavaVM(JavaVM ** p_vm,JNIEnv ** p_env,void * vm_args)259 jint JniInvocationImpl::JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
260   return JNI_CreateJavaVM_(p_vm, p_env, vm_args);
261 }
262 
JNI_GetCreatedJavaVMs(JavaVM ** vms,jsize size,jsize * vm_count)263 jint JniInvocationImpl::JNI_GetCreatedJavaVMs(JavaVM** vms, jsize size, jsize* vm_count) {
264   return JNI_GetCreatedJavaVMs_(vms, size, vm_count);
265 }
266 
FindSymbol(FUNC_POINTER * pointer,const char * symbol)267 bool JniInvocationImpl::FindSymbol(FUNC_POINTER* pointer, const char* symbol) {
268   *pointer = GetSymbol(handle_, symbol);
269   if (*pointer == NULL) {
270     ALOGE("Failed to find symbol %s: %s\n", symbol, GetError().c_str());
271     CloseLibrary(handle_);
272     handle_ = NULL;
273     return false;
274   }
275   return true;
276 }
277 
GetJniInvocation()278 JniInvocationImpl& JniInvocationImpl::GetJniInvocation() {
279   LOG_ALWAYS_FATAL_IF(jni_invocation_ == NULL,
280                       "Failed to create JniInvocation instance before using JNI invocation API");
281   return *jni_invocation_;
282 }
283 
JNI_GetDefaultJavaVMInitArgs(void * vm_args)284 MODULE_API jint JNI_GetDefaultJavaVMInitArgs(void* vm_args) {
285   return JniInvocationImpl::GetJniInvocation().JNI_GetDefaultJavaVMInitArgs(vm_args);
286 }
287 
JNI_CreateJavaVM(JavaVM ** p_vm,JNIEnv ** p_env,void * vm_args)288 MODULE_API jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
289   // Ensure any cached heap objects from previous VM instances are
290   // invalidated. There is no notification here that a VM is destroyed. These
291   // cached objects limit us to one VM instance per process.
292   JniConstants::Uninitialize();
293   return JniInvocationImpl::GetJniInvocation().JNI_CreateJavaVM(p_vm, p_env, vm_args);
294 }
295 
JNI_GetCreatedJavaVMs(JavaVM ** vms,jsize size,jsize * vm_count)296 MODULE_API jint JNI_GetCreatedJavaVMs(JavaVM** vms, jsize size, jsize* vm_count) {
297   return JniInvocationImpl::GetJniInvocation().JNI_GetCreatedJavaVMs(vms, size, vm_count);
298 }
299 
JniInvocationCreate()300 MODULE_API JniInvocationImpl* JniInvocationCreate() {
301   return new JniInvocationImpl();
302 }
303 
JniInvocationDestroy(JniInvocationImpl * instance)304 MODULE_API void JniInvocationDestroy(JniInvocationImpl* instance) {
305   delete instance;
306 }
307 
JniInvocationInit(JniInvocationImpl * instance,const char * library)308 MODULE_API int JniInvocationInit(JniInvocationImpl* instance, const char* library) {
309   return instance->Init(library) ? 1 : 0;
310 }
311 
JniInvocationGetLibrary(const char * library,char * buffer)312 MODULE_API const char* JniInvocationGetLibrary(const char* library, char* buffer) {
313   return JniInvocationImpl::GetLibrary(library, buffer);
314 }
315 
GetLibrary(const char * library,char * buffer,bool (* is_debuggable)(),int (* get_library_system_property)(char * buffer))316 MODULE_API const char* JniInvocation::GetLibrary(const char* library,
317                                                  char* buffer,
318                                                  bool (*is_debuggable)(),
319                                                  int (*get_library_system_property)(char* buffer)) {
320   return JniInvocationImpl::GetLibrary(library, buffer, is_debuggable, get_library_system_property);
321 }
322