blob: 51cba6d859a3a66c7840da82b878de04f1d49258 [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
Steven Moreland3544a932017-07-19 10:26:05 -070017#include <nativehelper/JniInvocation.h>
Brian Carlstromb2acfa22013-06-19 15:09:28 -070018
19#include <dlfcn.h>
20#include <stdlib.h>
Brian Carlstromfeeb36c2013-10-31 15:18:56 -070021#include <string.h>
Brian Carlstromb2acfa22013-06-19 15:09:28 -070022
23#include <cstddef>
24
25#define LOG_TAG "JniInvocation"
26#include "cutils/log.h"
27
Elliott Hughes68875712015-07-31 08:51:17 -070028#ifdef __ANDROID__
Dimitry Ivanov6bc946f2016-01-06 13:37:17 -080029#include <sys/system_properties.h>
Brian Carlstromb2acfa22013-06-19 15:09:28 -070030#endif
31
Tom Cherry3c461712017-12-14 00:00:15 -080032template <typename T>
33void UNUSED(const T&) {}
34
35bool 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
45int 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
Brian Carlstromb2acfa22013-06-19 15:09:28 -070054JniInvocation* JniInvocation::jni_invocation_ = NULL;
55
56JniInvocation::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
66JniInvocation::~JniInvocation() {
67 jni_invocation_ = NULL;
68 if (handle_ != NULL) {
69 dlclose(handle_);
70 }
71}
72
Narayan Kamath8c4708c2014-05-12 16:49:11 +010073static const char* kLibraryFallback = "libart.so";
Brian Carlstromfeeb36c2013-10-31 15:18:56 -070074
Ningsheng Jian88b84ec2014-09-17 13:34:09 +080075const char* JniInvocation::GetLibrary(const char* library, char* buffer) {
Tom Cherry3c461712017-12-14 00:00:15 -080076 return GetLibrary(library, buffer, &IsDebuggable, &GetLibrarySystemProperty);
77}
78
79const char* JniInvocation::GetLibrary(const char* library, char* buffer, bool (*is_debuggable)(),
80 int (*get_library_system_property)(char* buffer)) {
Elliott Hughes68875712015-07-31 08:51:17 -070081#ifdef __ANDROID__
Ningsheng Jian88b84ec2014-09-17 13:34:09 +080082 const char* default_library;
Andreas Gampe5f4f4aa2014-08-19 16:57:38 -070083
Tom Cherry3c461712017-12-14 00:00:15 -080084 if (!is_debuggable()) {
Andreas Gampe5f4f4aa2014-08-19 16:57:38 -070085 // Not a debuggable build.
86 // Do not allow arbitrary library. Ignore the library parameter. This
Ningsheng Jian88b84ec2014-09-17 13:34:09 +080087 // will also ignore the default library, but initialize to fallback
Andreas Gampe5f4f4aa2014-08-19 16:57:38 -070088 // for cleanliness.
89 library = kLibraryFallback;
Ningsheng Jian88b84ec2014-09-17 13:34:09 +080090 default_library = kLibraryFallback;
Andreas Gampe5f4f4aa2014-08-19 16:57:38 -070091 } else {
92 // Debuggable build.
93 // Accept the library parameter. For the case it is NULL, load the default
94 // library from the system property.
Ningsheng Jian88b84ec2014-09-17 13:34:09 +080095 if (buffer != NULL) {
Tom Cherry3c461712017-12-14 00:00:15 -080096 if (get_library_system_property(buffer) > 0) {
Dimitry Ivanov6bc946f2016-01-06 13:37:17 -080097 default_library = buffer;
98 } else {
99 default_library = kLibraryFallback;
100 }
Ningsheng Jian88b84ec2014-09-17 13:34:09 +0800101 } else {
102 // No buffer given, just use default fallback.
103 default_library = kLibraryFallback;
104 }
Andreas Gampe5f4f4aa2014-08-19 16:57:38 -0700105 }
Brian Carlstromb2acfa22013-06-19 15:09:28 -0700106#else
Ningsheng Jian88b84ec2014-09-17 13:34:09 +0800107 UNUSED(buffer);
Tom Cherry3c461712017-12-14 00:00:15 -0800108 UNUSED(is_debuggable);
109 UNUSED(get_library_system_property);
Brian Carlstromfeeb36c2013-10-31 15:18:56 -0700110 const char* default_library = kLibraryFallback;
Brian Carlstromb2acfa22013-06-19 15:09:28 -0700111#endif
112 if (library == NULL) {
113 library = default_library;
114 }
115
Andreas Gampe5f4f4aa2014-08-19 16:57:38 -0700116 return library;
117}
118
119bool JniInvocation::Init(const char* library) {
Elliott Hughes68875712015-07-31 08:51:17 -0700120#ifdef __ANDROID__
Dimitry Ivanov6bc946f2016-01-06 13:37:17 -0800121 char buffer[PROP_VALUE_MAX];
Ningsheng Jian88b84ec2014-09-17 13:34:09 +0800122#else
123 char* buffer = NULL;
124#endif
125 library = GetLibrary(library, buffer);
Alex Light6cf8e8d2016-06-02 15:26:23 -0700126 // 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);
Brian Carlstromb2acfa22013-06-19 15:09:28 -0700132 if (handle_ == NULL) {
Brian Carlstromfeeb36c2013-10-31 15:18:56 -0700133 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;
Alex Light6cf8e8d2016-06-02 15:26:23 -0700146 handle_ = dlopen(library, kDlopenFlags);
Brian Carlstromfeeb36c2013-10-31 15:18:56 -0700147 if (handle_ == NULL) {
148 ALOGE("Failed to dlopen %s: %s", library, dlerror());
149 return false;
150 }
Brian Carlstromb2acfa22013-06-19 15:09:28 -0700151 }
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
167jint JniInvocation::JNI_GetDefaultJavaVMInitArgs(void* vmargs) {
168 return JNI_GetDefaultJavaVMInitArgs_(vmargs);
169}
170
171jint JniInvocation::JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
172 return JNI_CreateJavaVM_(p_vm, p_env, vm_args);
173}
174
175jint JniInvocation::JNI_GetCreatedJavaVMs(JavaVM** vms, jsize size, jsize* vm_count) {
176 return JNI_GetCreatedJavaVMs_(vms, size, vm_count);
177}
178
179bool 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
190JniInvocation& 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
196extern "C" jint JNI_GetDefaultJavaVMInitArgs(void* vm_args) {
197 return JniInvocation::GetJniInvocation().JNI_GetDefaultJavaVMInitArgs(vm_args);
198}
199
200extern "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
204extern "C" jint JNI_GetCreatedJavaVMs(JavaVM** vms, jsize size, jsize* vm_count) {
205 return JniInvocation::GetJniInvocation().JNI_GetCreatedJavaVMs(vms, size, vm_count);
206}