blob: 6d992e69c30396f21322a2dd543f523cb0618aa9 [file] [log] [blame]
Brian Carlstromb2acfa22013-06-19 15:09:28 -07001/*
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
Orion Hodsonb01e7fe2018-11-07 06:07:50 +000017#include "nativehelper/JniInvocation.h"
Brian Carlstromb2acfa22013-06-19 15:09:28 -070018
Jerome Gaillardf0d42052019-03-12 15:17:22 +000019#ifdef _WIN32
20#include <windows.h>
21#else
Brian Carlstromb2acfa22013-06-19 15:09:28 -070022#include <dlfcn.h>
Jerome Gaillardf0d42052019-03-12 15:17:22 +000023#endif
Brian Carlstromb2acfa22013-06-19 15:09:28 -070024#include <stdlib.h>
Brian Carlstromfeeb36c2013-10-31 15:18:56 -070025#include <string.h>
Brian Carlstromb2acfa22013-06-19 15:09:28 -070026
27#include <cstddef>
28
29#define LOG_TAG "JniInvocation"
Logan Chienb7f05e42018-04-24 15:30:39 +080030#include <log/log.h>
Brian Carlstromb2acfa22013-06-19 15:09:28 -070031
Elliott Hughes68875712015-07-31 08:51:17 -070032#ifdef __ANDROID__
Dimitry Ivanov6bc946f2016-01-06 13:37:17 -080033#include <sys/system_properties.h>
Brian Carlstromb2acfa22013-06-19 15:09:28 -070034#endif
35
Jerome Gaillardf0d42052019-03-12 15:17:22 +000036#include "android-base/errors.h"
Orion Hodsonaadb3732018-11-21 12:58:34 +000037#include "JniConstants.h"
38
Orion Hodsonb01e7fe2018-11-07 06:07:50 +000039namespace {
40
Tom Cherry3c461712017-12-14 00:00:15 -080041template <typename T>
42void UNUSED(const T&) {}
43
44bool 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
54int 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
Jerome Gaillardf0d42052019-03-12 15:17:22 +000063#ifdef _WIN32
64#define FUNC_POINTER FARPROC
65#else
66#define FUNC_POINTER void*
67#endif
68
69void* 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
82int CloseLibrary(void* handle) {
83#ifdef _WIN32
84 return FreeLibrary(static_cast<HMODULE>(handle));
85#else
86 return dlclose(handle);
87#endif
88}
89
90FUNC_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
98std::string GetError() {
99#ifdef _WIN32
100 return android::base::SystemErrorCodeToString(GetLastError());
101#else
102 return std::string(dlerror());
103#endif
104}
105
Orion Hodsonb01e7fe2018-11-07 06:07:50 +0000106} // namespace
Brian Carlstromb2acfa22013-06-19 15:09:28 -0700107
Orion Hodsonb01e7fe2018-11-07 06:07:50 +0000108struct 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
Jerome Gaillardf0d42052019-03-12 15:17:22 +0000132 bool FindSymbol(FUNC_POINTER* pointer, const char* symbol);
Orion Hodsonb01e7fe2018-11-07 06:07:50 +0000133
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.
148static_assert(sizeof(JniInvocationImpl) == 4 * sizeof(uintptr_t));
149
150JniInvocationImpl* JniInvocationImpl::jni_invocation_ = NULL;
151
152JniInvocationImpl::JniInvocationImpl() :
Brian Carlstromb2acfa22013-06-19 15:09:28 -0700153 handle_(NULL),
154 JNI_GetDefaultJavaVMInitArgs_(NULL),
155 JNI_CreateJavaVM_(NULL),
156 JNI_GetCreatedJavaVMs_(NULL) {
Brian Carlstromb2acfa22013-06-19 15:09:28 -0700157 LOG_ALWAYS_FATAL_IF(jni_invocation_ != NULL, "JniInvocation instance already initialized");
158 jni_invocation_ = this;
159}
160
Orion Hodsonb01e7fe2018-11-07 06:07:50 +0000161JniInvocationImpl::~JniInvocationImpl() {
Brian Carlstromb2acfa22013-06-19 15:09:28 -0700162 jni_invocation_ = NULL;
163 if (handle_ != NULL) {
Jerome Gaillardf0d42052019-03-12 15:17:22 +0000164 CloseLibrary(handle_);
Brian Carlstromb2acfa22013-06-19 15:09:28 -0700165 }
166}
167
Narayan Kamath8c4708c2014-05-12 16:49:11 +0100168static const char* kLibraryFallback = "libart.so";
Brian Carlstromfeeb36c2013-10-31 15:18:56 -0700169
Orion Hodsonb01e7fe2018-11-07 06:07:50 +0000170const char* JniInvocationImpl::GetLibrary(const char* library,
171 char* buffer,
172 bool (*is_debuggable)(),
173 int (*get_library_system_property)(char* buffer)) {
Elliott Hughes68875712015-07-31 08:51:17 -0700174#ifdef __ANDROID__
Ningsheng Jian88b84ec2014-09-17 13:34:09 +0800175 const char* default_library;
Andreas Gampe5f4f4aa2014-08-19 16:57:38 -0700176
Tom Cherry3c461712017-12-14 00:00:15 -0800177 if (!is_debuggable()) {
Andreas Gampe5f4f4aa2014-08-19 16:57:38 -0700178 // Not a debuggable build.
179 // Do not allow arbitrary library. Ignore the library parameter. This
Ningsheng Jian88b84ec2014-09-17 13:34:09 +0800180 // will also ignore the default library, but initialize to fallback
Andreas Gampe5f4f4aa2014-08-19 16:57:38 -0700181 // for cleanliness.
182 library = kLibraryFallback;
Ningsheng Jian88b84ec2014-09-17 13:34:09 +0800183 default_library = kLibraryFallback;
Andreas Gampe5f4f4aa2014-08-19 16:57:38 -0700184 } else {
185 // Debuggable build.
186 // Accept the library parameter. For the case it is NULL, load the default
187 // library from the system property.
Ningsheng Jian88b84ec2014-09-17 13:34:09 +0800188 if (buffer != NULL) {
Tom Cherry3c461712017-12-14 00:00:15 -0800189 if (get_library_system_property(buffer) > 0) {
Dimitry Ivanov6bc946f2016-01-06 13:37:17 -0800190 default_library = buffer;
191 } else {
192 default_library = kLibraryFallback;
193 }
Ningsheng Jian88b84ec2014-09-17 13:34:09 +0800194 } else {
195 // No buffer given, just use default fallback.
196 default_library = kLibraryFallback;
197 }
Andreas Gampe5f4f4aa2014-08-19 16:57:38 -0700198 }
Brian Carlstromb2acfa22013-06-19 15:09:28 -0700199#else
Ningsheng Jian88b84ec2014-09-17 13:34:09 +0800200 UNUSED(buffer);
Tom Cherry3c461712017-12-14 00:00:15 -0800201 UNUSED(is_debuggable);
202 UNUSED(get_library_system_property);
Brian Carlstromfeeb36c2013-10-31 15:18:56 -0700203 const char* default_library = kLibraryFallback;
Brian Carlstromb2acfa22013-06-19 15:09:28 -0700204#endif
205 if (library == NULL) {
206 library = default_library;
207 }
208
Andreas Gampe5f4f4aa2014-08-19 16:57:38 -0700209 return library;
210}
211
Orion Hodsonb01e7fe2018-11-07 06:07:50 +0000212bool JniInvocationImpl::Init(const char* library) {
Elliott Hughes68875712015-07-31 08:51:17 -0700213#ifdef __ANDROID__
Dimitry Ivanov6bc946f2016-01-06 13:37:17 -0800214 char buffer[PROP_VALUE_MAX];
Ningsheng Jian88b84ec2014-09-17 13:34:09 +0800215#else
216 char* buffer = NULL;
217#endif
218 library = GetLibrary(library, buffer);
Jerome Gaillardf0d42052019-03-12 15:17:22 +0000219 handle_ = OpenLibrary(library);
Brian Carlstromb2acfa22013-06-19 15:09:28 -0700220 if (handle_ == NULL) {
Brian Carlstromfeeb36c2013-10-31 15:18:56 -0700221 if (strcmp(library, kLibraryFallback) == 0) {
222 // Nothing else to try.
Jerome Gaillardf0d42052019-03-12 15:17:22 +0000223 ALOGE("Failed to dlopen %s: %s", library, GetError().c_str());
Brian Carlstromfeeb36c2013-10-31 15:18:56 -0700224 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",
Jerome Gaillardf0d42052019-03-12 15:17:22 +0000232 library, kLibraryFallback, GetError().c_str());
Brian Carlstromfeeb36c2013-10-31 15:18:56 -0700233 library = kLibraryFallback;
Jerome Gaillardf0d42052019-03-12 15:17:22 +0000234 handle_ = OpenLibrary(library);
Brian Carlstromfeeb36c2013-10-31 15:18:56 -0700235 if (handle_ == NULL) {
Jerome Gaillardf0d42052019-03-12 15:17:22 +0000236 ALOGE("Failed to dlopen %s: %s", library, GetError().c_str());
Brian Carlstromfeeb36c2013-10-31 15:18:56 -0700237 return false;
238 }
Brian Carlstromb2acfa22013-06-19 15:09:28 -0700239 }
Jerome Gaillardf0d42052019-03-12 15:17:22 +0000240 if (!FindSymbol(reinterpret_cast<FUNC_POINTER*>(&JNI_GetDefaultJavaVMInitArgs_),
Brian Carlstromb2acfa22013-06-19 15:09:28 -0700241 "JNI_GetDefaultJavaVMInitArgs")) {
242 return false;
243 }
Jerome Gaillardf0d42052019-03-12 15:17:22 +0000244 if (!FindSymbol(reinterpret_cast<FUNC_POINTER*>(&JNI_CreateJavaVM_),
Brian Carlstromb2acfa22013-06-19 15:09:28 -0700245 "JNI_CreateJavaVM")) {
246 return false;
247 }
Jerome Gaillardf0d42052019-03-12 15:17:22 +0000248 if (!FindSymbol(reinterpret_cast<FUNC_POINTER*>(&JNI_GetCreatedJavaVMs_),
Brian Carlstromb2acfa22013-06-19 15:09:28 -0700249 "JNI_GetCreatedJavaVMs")) {
250 return false;
251 }
252 return true;
253}
254
Orion Hodsonb01e7fe2018-11-07 06:07:50 +0000255jint JniInvocationImpl::JNI_GetDefaultJavaVMInitArgs(void* vmargs) {
Brian Carlstromb2acfa22013-06-19 15:09:28 -0700256 return JNI_GetDefaultJavaVMInitArgs_(vmargs);
257}
258
Orion Hodsonb01e7fe2018-11-07 06:07:50 +0000259jint JniInvocationImpl::JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
Brian Carlstromb2acfa22013-06-19 15:09:28 -0700260 return JNI_CreateJavaVM_(p_vm, p_env, vm_args);
261}
262
Orion Hodsonb01e7fe2018-11-07 06:07:50 +0000263jint JniInvocationImpl::JNI_GetCreatedJavaVMs(JavaVM** vms, jsize size, jsize* vm_count) {
Brian Carlstromb2acfa22013-06-19 15:09:28 -0700264 return JNI_GetCreatedJavaVMs_(vms, size, vm_count);
265}
266
Jerome Gaillardf0d42052019-03-12 15:17:22 +0000267bool JniInvocationImpl::FindSymbol(FUNC_POINTER* pointer, const char* symbol) {
268 *pointer = GetSymbol(handle_, symbol);
Brian Carlstromb2acfa22013-06-19 15:09:28 -0700269 if (*pointer == NULL) {
Jerome Gaillardf0d42052019-03-12 15:17:22 +0000270 ALOGE("Failed to find symbol %s: %s\n", symbol, GetError().c_str());
271 CloseLibrary(handle_);
Brian Carlstromb2acfa22013-06-19 15:09:28 -0700272 handle_ = NULL;
273 return false;
274 }
275 return true;
276}
277
Orion Hodsonb01e7fe2018-11-07 06:07:50 +0000278JniInvocationImpl& JniInvocationImpl::GetJniInvocation() {
Brian Carlstromb2acfa22013-06-19 15:09:28 -0700279 LOG_ALWAYS_FATAL_IF(jni_invocation_ == NULL,
280 "Failed to create JniInvocation instance before using JNI invocation API");
281 return *jni_invocation_;
282}
283
Orion Hodsonb01e7fe2018-11-07 06:07:50 +0000284MODULE_API jint JNI_GetDefaultJavaVMInitArgs(void* vm_args) {
285 return JniInvocationImpl::GetJniInvocation().JNI_GetDefaultJavaVMInitArgs(vm_args);
Brian Carlstromb2acfa22013-06-19 15:09:28 -0700286}
287
Orion Hodsonb01e7fe2018-11-07 06:07:50 +0000288MODULE_API jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
Orion Hodsonaadb3732018-11-21 12:58:34 +0000289 // 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();
Orion Hodsonb01e7fe2018-11-07 06:07:50 +0000293 return JniInvocationImpl::GetJniInvocation().JNI_CreateJavaVM(p_vm, p_env, vm_args);
Brian Carlstromb2acfa22013-06-19 15:09:28 -0700294}
295
Orion Hodsonb01e7fe2018-11-07 06:07:50 +0000296MODULE_API jint JNI_GetCreatedJavaVMs(JavaVM** vms, jsize size, jsize* vm_count) {
297 return JniInvocationImpl::GetJniInvocation().JNI_GetCreatedJavaVMs(vms, size, vm_count);
298}
299
300MODULE_API JniInvocationImpl* JniInvocationCreate() {
301 return new JniInvocationImpl();
302}
303
304MODULE_API void JniInvocationDestroy(JniInvocationImpl* instance) {
305 delete instance;
306}
307
308MODULE_API int JniInvocationInit(JniInvocationImpl* instance, const char* library) {
309 return instance->Init(library) ? 1 : 0;
310}
311
312MODULE_API const char* JniInvocationGetLibrary(const char* library, char* buffer) {
313 return JniInvocationImpl::GetLibrary(library, buffer);
314}
315
316MODULE_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);
Brian Carlstromb2acfa22013-06-19 15:09:28 -0700321}