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