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
121 jint JNI_GetDefaultJavaVMInitArgs(void* vmargs);
122 jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args);
123 jint JNI_GetCreatedJavaVMs(JavaVM** vms, jsize size, jsize* vm_count);
124
125 private:
126 JniInvocationImpl(const JniInvocationImpl&) = delete;
127 JniInvocationImpl& operator=(const JniInvocationImpl&) = delete;
128
129 bool FindSymbol(FUNC_POINTER* pointer, const char* symbol);
130
131 static JniInvocationImpl* jni_invocation_;
132
133 // Handle to library opened with dlopen(). Library exports
134 // JNI_GetDefaultJavaVMInitArgs, JNI_CreateJavaVM, JNI_GetCreatedJavaVMs.
135 void* handle_;
136 jint (*JNI_GetDefaultJavaVMInitArgs_)(void*);
137 jint (*JNI_CreateJavaVM_)(JavaVM**, JNIEnv**, void*);
138 jint (*JNI_GetCreatedJavaVMs_)(JavaVM**, jsize, jsize*);
139
140 friend class JNIInvocation_Debuggable_Test;
141 friend class JNIInvocation_NonDebuggable_Test;
142 };
143
144 // Check JniInvocationImpl size is same as fields, e.g. no vtable present.
145 static_assert(sizeof(JniInvocationImpl) == 4 * sizeof(uintptr_t));
146
147 JniInvocationImpl* JniInvocationImpl::jni_invocation_ = NULL;
148
JniInvocationImpl()149 JniInvocationImpl::JniInvocationImpl() :
150 handle_(NULL),
151 JNI_GetDefaultJavaVMInitArgs_(NULL),
152 JNI_CreateJavaVM_(NULL),
153 JNI_GetCreatedJavaVMs_(NULL) {
154 LOG_ALWAYS_FATAL_IF(jni_invocation_ != NULL, "JniInvocation instance already initialized");
155 jni_invocation_ = this;
156 }
157
~JniInvocationImpl()158 JniInvocationImpl::~JniInvocationImpl() {
159 jni_invocation_ = NULL;
160 if (handle_ != NULL) {
161 CloseLibrary(handle_);
162 }
163 }
164
165 static const char* kLibraryFallback = "libart.so";
166
GetLibrary(const char * library,char * buffer,bool (* is_debuggable)(),int (* get_library_system_property)(char * buffer))167 const char* JniInvocationImpl::GetLibrary(const char* library,
168 char* buffer,
169 bool (*is_debuggable)(),
170 int (*get_library_system_property)(char* buffer)) {
171 #ifdef __ANDROID__
172 const char* default_library;
173
174 if (!is_debuggable()) {
175 // Not a debuggable build.
176 // Do not allow arbitrary library. Ignore the library parameter. This
177 // will also ignore the default library, but initialize to fallback
178 // for cleanliness.
179 library = kLibraryFallback;
180 default_library = kLibraryFallback;
181 } else {
182 // Debuggable build.
183 // Accept the library parameter. For the case it is NULL, load the default
184 // library from the system property.
185 if (buffer != NULL) {
186 if (get_library_system_property(buffer) > 0) {
187 default_library = buffer;
188 } else {
189 default_library = kLibraryFallback;
190 }
191 } else {
192 // No buffer given, just use default fallback.
193 default_library = kLibraryFallback;
194 }
195 }
196 #else
197 UNUSED(buffer);
198 UNUSED(is_debuggable);
199 UNUSED(get_library_system_property);
200 const char* default_library = kLibraryFallback;
201 #endif
202 if (library == NULL) {
203 library = default_library;
204 }
205
206 return library;
207 }
208
Init(const char * library)209 bool JniInvocationImpl::Init(const char* library) {
210 #ifdef __ANDROID__
211 char buffer[PROP_VALUE_MAX];
212 #else
213 char* buffer = NULL;
214 #endif
215 library = GetLibrary(library, buffer);
216 handle_ = OpenLibrary(library);
217 if (handle_ == NULL) {
218 if (strcmp(library, kLibraryFallback) == 0) {
219 // Nothing else to try.
220 ALOGE("Failed to dlopen %s: %s", library, GetError().c_str());
221 return false;
222 }
223 // Note that this is enough to get something like the zygote
224 // running, we can't property_set here to fix this for the future
225 // because we are root and not the system user. See
226 // RuntimeInit.commonInit for where we fix up the property to
227 // avoid future fallbacks. http://b/11463182
228 ALOGW("Falling back from %s to %s after dlopen error: %s",
229 library, kLibraryFallback, GetError().c_str());
230 library = kLibraryFallback;
231 handle_ = OpenLibrary(library);
232 if (handle_ == NULL) {
233 ALOGE("Failed to dlopen %s: %s", library, GetError().c_str());
234 return false;
235 }
236 }
237 if (!FindSymbol(reinterpret_cast<FUNC_POINTER*>(&JNI_GetDefaultJavaVMInitArgs_),
238 "JNI_GetDefaultJavaVMInitArgs")) {
239 return false;
240 }
241 if (!FindSymbol(reinterpret_cast<FUNC_POINTER*>(&JNI_CreateJavaVM_),
242 "JNI_CreateJavaVM")) {
243 return false;
244 }
245 if (!FindSymbol(reinterpret_cast<FUNC_POINTER*>(&JNI_GetCreatedJavaVMs_),
246 "JNI_GetCreatedJavaVMs")) {
247 return false;
248 }
249 return true;
250 }
251
JNI_GetDefaultJavaVMInitArgs(void * vmargs)252 jint JniInvocationImpl::JNI_GetDefaultJavaVMInitArgs(void* vmargs) {
253 return JNI_GetDefaultJavaVMInitArgs_(vmargs);
254 }
255
JNI_CreateJavaVM(JavaVM ** p_vm,JNIEnv ** p_env,void * vm_args)256 jint JniInvocationImpl::JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
257 return JNI_CreateJavaVM_(p_vm, p_env, vm_args);
258 }
259
JNI_GetCreatedJavaVMs(JavaVM ** vms,jsize size,jsize * vm_count)260 jint JniInvocationImpl::JNI_GetCreatedJavaVMs(JavaVM** vms, jsize size, jsize* vm_count) {
261 return JNI_GetCreatedJavaVMs_(vms, size, vm_count);
262 }
263
FindSymbol(FUNC_POINTER * pointer,const char * symbol)264 bool JniInvocationImpl::FindSymbol(FUNC_POINTER* pointer, const char* symbol) {
265 *pointer = GetSymbol(handle_, symbol);
266 if (*pointer == NULL) {
267 ALOGE("Failed to find symbol %s: %s\n", symbol, GetError().c_str());
268 CloseLibrary(handle_);
269 handle_ = NULL;
270 return false;
271 }
272 return true;
273 }
274
GetJniInvocation()275 JniInvocationImpl& JniInvocationImpl::GetJniInvocation() {
276 LOG_ALWAYS_FATAL_IF(jni_invocation_ == NULL,
277 "Failed to create JniInvocation instance before using JNI invocation API");
278 return *jni_invocation_;
279 }
280
JNI_GetDefaultJavaVMInitArgs(void * vm_args)281 jint JNI_GetDefaultJavaVMInitArgs(void* vm_args) {
282 return JniInvocationImpl::GetJniInvocation().JNI_GetDefaultJavaVMInitArgs(vm_args);
283 }
284
JNI_CreateJavaVM(JavaVM ** p_vm,JNIEnv ** p_env,void * vm_args)285 jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
286 // Ensure any cached heap objects from previous VM instances are
287 // invalidated. There is no notification here that a VM is destroyed. These
288 // cached objects limit us to one VM instance per process.
289 JniConstants::Uninitialize();
290 return JniInvocationImpl::GetJniInvocation().JNI_CreateJavaVM(p_vm, p_env, vm_args);
291 }
292
JNI_GetCreatedJavaVMs(JavaVM ** vms,jsize size,jsize * vm_count)293 jint JNI_GetCreatedJavaVMs(JavaVM** vms, jsize size, jsize* vm_count) {
294 return JniInvocationImpl::GetJniInvocation().JNI_GetCreatedJavaVMs(vms, size, vm_count);
295 }
296
GetLibrary(const char * library,char * buffer,bool (* is_debuggable)(),int (* get_library_system_property)(char * buffer))297 const char* JniInvocation::GetLibrary(const char* library,
298 char* buffer,
299 bool (*is_debuggable)(),
300 int (*get_library_system_property)(char* buffer)) {
301 return JniInvocationImpl::GetLibrary(library, buffer, is_debuggable, get_library_system_property);
302 }
303
JniInvocationCreate()304 JniInvocationImpl* JniInvocationCreate() {
305 return new JniInvocationImpl();
306 }
307
JniInvocationDestroy(JniInvocationImpl * instance)308 void JniInvocationDestroy(JniInvocationImpl* instance) {
309 delete instance;
310 }
311
JniInvocationInit(JniInvocationImpl * instance,const char * library)312 int JniInvocationInit(JniInvocationImpl* instance, const char* library) {
313 return instance->Init(library) ? 1 : 0;
314 }
315
JniInvocationGetLibrary(const char * library,char * buffer)316 const char* JniInvocationGetLibrary(const char* library, char* buffer) {
317 return JniInvocationImpl::GetLibrary(library, buffer);
318 }
319