blob: 031dcb3788b697c2d41e1781c4d758e7ee9c7610 [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
32JniInvocation* JniInvocation::jni_invocation_ = NULL;
33
34JniInvocation::JniInvocation() :
35 handle_(NULL),
36 JNI_GetDefaultJavaVMInitArgs_(NULL),
37 JNI_CreateJavaVM_(NULL),
38 JNI_GetCreatedJavaVMs_(NULL) {
39
40 LOG_ALWAYS_FATAL_IF(jni_invocation_ != NULL, "JniInvocation instance already initialized");
41 jni_invocation_ = this;
42}
43
44JniInvocation::~JniInvocation() {
45 jni_invocation_ = NULL;
46 if (handle_ != NULL) {
47 dlclose(handle_);
48 }
49}
50
Elliott Hughes68875712015-07-31 08:51:17 -070051#ifdef __ANDROID__
Brian Carlstrom3a4f0c32014-05-28 14:31:47 -070052static const char* kLibrarySystemProperty = "persist.sys.dalvik.vm.lib.2";
Andreas Gampe5f4f4aa2014-08-19 16:57:38 -070053static const char* kDebuggableSystemProperty = "ro.debuggable";
Brian Carlstromfeeb36c2013-10-31 15:18:56 -070054#endif
Narayan Kamath8c4708c2014-05-12 16:49:11 +010055static const char* kLibraryFallback = "libart.so";
Brian Carlstromfeeb36c2013-10-31 15:18:56 -070056
Ningsheng Jian88b84ec2014-09-17 13:34:09 +080057template<typename T> void UNUSED(const T&) {}
58
59const char* JniInvocation::GetLibrary(const char* library, char* buffer) {
Elliott Hughes68875712015-07-31 08:51:17 -070060#ifdef __ANDROID__
Ningsheng Jian88b84ec2014-09-17 13:34:09 +080061 const char* default_library;
Andreas Gampe5f4f4aa2014-08-19 16:57:38 -070062
Dimitry Ivanov6bc946f2016-01-06 13:37:17 -080063 char debuggable[PROP_VALUE_MAX];
64 __system_property_get(kDebuggableSystemProperty, debuggable);
Andreas Gampe5f4f4aa2014-08-19 16:57:38 -070065
66 if (strcmp(debuggable, "1") != 0) {
67 // Not a debuggable build.
68 // Do not allow arbitrary library. Ignore the library parameter. This
Ningsheng Jian88b84ec2014-09-17 13:34:09 +080069 // will also ignore the default library, but initialize to fallback
Andreas Gampe5f4f4aa2014-08-19 16:57:38 -070070 // for cleanliness.
71 library = kLibraryFallback;
Ningsheng Jian88b84ec2014-09-17 13:34:09 +080072 default_library = kLibraryFallback;
Andreas Gampe5f4f4aa2014-08-19 16:57:38 -070073 } else {
74 // Debuggable build.
75 // Accept the library parameter. For the case it is NULL, load the default
76 // library from the system property.
Ningsheng Jian88b84ec2014-09-17 13:34:09 +080077 if (buffer != NULL) {
Dimitry Ivanov6bc946f2016-01-06 13:37:17 -080078 if (__system_property_get(kLibrarySystemProperty, buffer) > 0) {
79 default_library = buffer;
80 } else {
81 default_library = kLibraryFallback;
82 }
Ningsheng Jian88b84ec2014-09-17 13:34:09 +080083 } else {
84 // No buffer given, just use default fallback.
85 default_library = kLibraryFallback;
86 }
Andreas Gampe5f4f4aa2014-08-19 16:57:38 -070087 }
Brian Carlstromb2acfa22013-06-19 15:09:28 -070088#else
Ningsheng Jian88b84ec2014-09-17 13:34:09 +080089 UNUSED(buffer);
Brian Carlstromfeeb36c2013-10-31 15:18:56 -070090 const char* default_library = kLibraryFallback;
Brian Carlstromb2acfa22013-06-19 15:09:28 -070091#endif
92 if (library == NULL) {
93 library = default_library;
94 }
95
Andreas Gampe5f4f4aa2014-08-19 16:57:38 -070096 return library;
97}
98
99bool JniInvocation::Init(const char* library) {
Elliott Hughes68875712015-07-31 08:51:17 -0700100#ifdef __ANDROID__
Dimitry Ivanov6bc946f2016-01-06 13:37:17 -0800101 char buffer[PROP_VALUE_MAX];
Ningsheng Jian88b84ec2014-09-17 13:34:09 +0800102#else
103 char* buffer = NULL;
104#endif
105 library = GetLibrary(library, buffer);
Alex Light6cf8e8d2016-06-02 15:26:23 -0700106 // Load with RTLD_NODELETE in order to ensure that libart.so is not unmapped when it is closed.
107 // This is due to the fact that it is possible that some threads might have yet to finish
108 // exiting even after JNI_DeleteJavaVM returns, which can lead to segfaults if the library is
109 // unloaded.
110 const int kDlopenFlags = RTLD_NOW | RTLD_NODELETE;
111 handle_ = dlopen(library, kDlopenFlags);
Brian Carlstromb2acfa22013-06-19 15:09:28 -0700112 if (handle_ == NULL) {
Brian Carlstromfeeb36c2013-10-31 15:18:56 -0700113 if (strcmp(library, kLibraryFallback) == 0) {
114 // Nothing else to try.
115 ALOGE("Failed to dlopen %s: %s", library, dlerror());
116 return false;
117 }
118 // Note that this is enough to get something like the zygote
119 // running, we can't property_set here to fix this for the future
120 // because we are root and not the system user. See
121 // RuntimeInit.commonInit for where we fix up the property to
122 // avoid future fallbacks. http://b/11463182
123 ALOGW("Falling back from %s to %s after dlopen error: %s",
124 library, kLibraryFallback, dlerror());
125 library = kLibraryFallback;
Alex Light6cf8e8d2016-06-02 15:26:23 -0700126 handle_ = dlopen(library, kDlopenFlags);
Brian Carlstromfeeb36c2013-10-31 15:18:56 -0700127 if (handle_ == NULL) {
128 ALOGE("Failed to dlopen %s: %s", library, dlerror());
129 return false;
130 }
Brian Carlstromb2acfa22013-06-19 15:09:28 -0700131 }
132 if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetDefaultJavaVMInitArgs_),
133 "JNI_GetDefaultJavaVMInitArgs")) {
134 return false;
135 }
136 if (!FindSymbol(reinterpret_cast<void**>(&JNI_CreateJavaVM_),
137 "JNI_CreateJavaVM")) {
138 return false;
139 }
140 if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetCreatedJavaVMs_),
141 "JNI_GetCreatedJavaVMs")) {
142 return false;
143 }
144 return true;
145}
146
147jint JniInvocation::JNI_GetDefaultJavaVMInitArgs(void* vmargs) {
148 return JNI_GetDefaultJavaVMInitArgs_(vmargs);
149}
150
151jint JniInvocation::JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
152 return JNI_CreateJavaVM_(p_vm, p_env, vm_args);
153}
154
155jint JniInvocation::JNI_GetCreatedJavaVMs(JavaVM** vms, jsize size, jsize* vm_count) {
156 return JNI_GetCreatedJavaVMs_(vms, size, vm_count);
157}
158
159bool JniInvocation::FindSymbol(void** pointer, const char* symbol) {
160 *pointer = dlsym(handle_, symbol);
161 if (*pointer == NULL) {
162 ALOGE("Failed to find symbol %s: %s\n", symbol, dlerror());
163 dlclose(handle_);
164 handle_ = NULL;
165 return false;
166 }
167 return true;
168}
169
170JniInvocation& JniInvocation::GetJniInvocation() {
171 LOG_ALWAYS_FATAL_IF(jni_invocation_ == NULL,
172 "Failed to create JniInvocation instance before using JNI invocation API");
173 return *jni_invocation_;
174}
175
176extern "C" jint JNI_GetDefaultJavaVMInitArgs(void* vm_args) {
177 return JniInvocation::GetJniInvocation().JNI_GetDefaultJavaVMInitArgs(vm_args);
178}
179
180extern "C" jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
181 return JniInvocation::GetJniInvocation().JNI_CreateJavaVM(p_vm, p_env, vm_args);
182}
183
184extern "C" jint JNI_GetCreatedJavaVMs(JavaVM** vms, jsize size, jsize* vm_count) {
185 return JniInvocation::GetJniInvocation().JNI_GetCreatedJavaVMs(vms, size, vm_count);
186}