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 "include_platform/nativehelper/JniInvocation.h"
18
19 #define LOG_TAG "JniInvocation"
20 #include "ALog-priv.h"
21
22 #if defined(__ANDROID__)
23 #include <sys/system_properties.h>
24 #endif
25
26 #include <errno.h>
27 #include <jni.h>
28 #include <stdbool.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <unistd.h>
34
35 #include "DlHelp.h"
36
37 // Name the default library providing the JNI Invocation API.
38 static const char* kDefaultJniInvocationLibrary = "libart.so";
39 static const char* kDebugJniInvocationLibrary = "libartd.so";
40 #if defined(__LP64__)
41 #define LIB_DIR "lib64"
42 #else
43 #define LIB_DIR "lib"
44 #endif
45 static const char* kDebugJniInvocationLibraryPath = "/apex/com.android.art/" LIB_DIR "/libartd.so";
46
47 struct JniInvocationImpl {
48 // Name of library providing JNI_ method implementations.
49 const char* jni_provider_library_name;
50
51 // Opaque pointer to shared library from dlopen / LoadLibrary.
52 void* jni_provider_library;
53
54 // Function pointers to methods in JNI provider.
55 jint (*JNI_GetDefaultJavaVMInitArgs)(void*);
56 jint (*JNI_CreateJavaVM)(JavaVM**, JNIEnv**, void*);
57 jint (*JNI_GetCreatedJavaVMs)(JavaVM**, jsize, jsize*);
58 };
59
60 static struct JniInvocationImpl g_impl;
61
62 //
63 // Internal helpers.
64 //
65
66 #define UNUSED(x) (x) = (x)
67
RunningOnVM()68 static bool RunningOnVM() {
69 const char* on_vm = getenv("ART_TEST_ON_VM");
70 return on_vm != NULL && strcmp("true", on_vm) == 0;
71 }
72
IsDebuggable()73 static bool IsDebuggable() {
74 #ifdef __ANDROID__
75 if (RunningOnVM()) {
76 // VM environment is always treated as debuggable, as it has no system properties to query.
77 return true;
78 }
79
80 char debuggable[PROP_VALUE_MAX] = {0};
81 __system_property_get("ro.debuggable", debuggable);
82 return strcmp(debuggable, "1") == 0;
83 #else
84 // Host is always treated as debuggable, which allows choice of library to be overridden.
85 return true;
86 #endif
87 }
88
GetLibrarySystemProperty(char * buffer)89 static int GetLibrarySystemProperty(char* buffer) {
90 #ifdef __ANDROID__
91 return __system_property_get("persist.sys.dalvik.vm.lib.2", buffer);
92 #else
93 // Host does not use properties.
94 UNUSED(buffer);
95 return 0;
96 #endif
97 }
98
FindSymbol(DlLibrary library,const char * symbol)99 static DlSymbol FindSymbol(DlLibrary library, const char* symbol) {
100 DlSymbol s = DlGetSymbol(library, symbol);
101 if (s == NULL) {
102 ALOGE("Failed to find symbol: %s", symbol);
103 }
104 return s;
105 }
106
107 //
108 // Exported functions for JNI based VM management from JNI spec.
109 //
110
JNI_GetDefaultJavaVMInitArgs(void * vmargs)111 jint JNI_GetDefaultJavaVMInitArgs(void* vmargs) {
112 ALOG_ALWAYS_FATAL_IF(NULL == g_impl.JNI_GetDefaultJavaVMInitArgs, "Runtime library not loaded.");
113 return g_impl.JNI_GetDefaultJavaVMInitArgs(vmargs);
114 }
115
JNI_CreateJavaVM(JavaVM ** p_vm,JNIEnv ** p_env,void * vm_args)116 jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
117 ALOG_ALWAYS_FATAL_IF(NULL == g_impl.JNI_CreateJavaVM, "Runtime library not loaded.");
118 return g_impl.JNI_CreateJavaVM(p_vm, p_env, vm_args);
119 }
120
JNI_GetCreatedJavaVMs(JavaVM ** vms,jsize size,jsize * vm_count)121 jint JNI_GetCreatedJavaVMs(JavaVM** vms, jsize size, jsize* vm_count) {
122 if (NULL == g_impl.JNI_GetCreatedJavaVMs) {
123 *vm_count = 0;
124 return JNI_OK;
125 }
126 return g_impl.JNI_GetCreatedJavaVMs(vms, size, vm_count);
127 }
128
129 //
130 // JniInvocation functions for setting up JNI functions.
131 //
132
JniInvocationGetLibraryWith(const char * library,bool is_debuggable,const char * system_preferred_library)133 const char* JniInvocationGetLibraryWith(const char* library,
134 bool is_debuggable,
135 const char* system_preferred_library) {
136 if (is_debuggable) {
137 // Debuggable property is set. Allow library providing JNI Invocation API to be overridden.
138
139 // Choose the library parameter (if provided).
140 if (library != NULL) {
141 return library;
142 }
143
144 // If the debug library is installed, use it.
145 // TODO(b/216099383): Do this in the test harness instead.
146 struct stat st;
147 if (stat(kDebugJniInvocationLibraryPath, &st) == 0) {
148 return kDebugJniInvocationLibrary;
149 } else if (errno != ENOENT) {
150 ALOGW("Failed to stat %s: %s", kDebugJniInvocationLibraryPath, strerror(errno));
151 }
152
153 // Choose the system_preferred_library (if provided).
154 if (system_preferred_library != NULL) {
155 return system_preferred_library;
156 }
157
158 }
159 return kDefaultJniInvocationLibrary;
160 }
161
JniInvocationGetLibrary(const char * library,char * buffer)162 const char* JniInvocationGetLibrary(const char* library, char* buffer) {
163 bool debuggable = IsDebuggable();
164 const char* system_preferred_library = NULL;
165 if (buffer != NULL && (GetLibrarySystemProperty(buffer) > 0)) {
166 system_preferred_library = buffer;
167 }
168 return JniInvocationGetLibraryWith(library, debuggable, system_preferred_library);
169 }
170
JniInvocationCreate()171 struct JniInvocationImpl* JniInvocationCreate() {
172 // Android only supports a single JniInvocation instance and only a single JavaVM.
173 if (g_impl.jni_provider_library != NULL) {
174 return NULL;
175 }
176 return &g_impl;
177 }
178
JniInvocationInit(struct JniInvocationImpl * instance,const char * library_name)179 bool JniInvocationInit(struct JniInvocationImpl* instance, const char* library_name) {
180 #ifdef __ANDROID__
181 char buffer[PROP_VALUE_MAX];
182 #else
183 char* buffer = NULL;
184 #endif
185 library_name = JniInvocationGetLibrary(library_name, buffer);
186 DlLibrary library = DlOpenLibrary(library_name);
187 if (library == NULL) {
188 if (strcmp(library_name, kDefaultJniInvocationLibrary) == 0) {
189 // Nothing else to try.
190 ALOGE("Failed to dlopen %s: %s", library_name, DlGetError());
191 return false;
192 }
193 // Note that this is enough to get something like the zygote
194 // running, we can't property_set here to fix this for the future
195 // because we are root and not the system user. See
196 // RuntimeInit.commonInit for where we fix up the property to
197 // avoid future fallbacks. http://b/11463182
198 ALOGW("Falling back from %s to %s after dlopen error: %s",
199 library_name, kDefaultJniInvocationLibrary, DlGetError());
200 library_name = kDefaultJniInvocationLibrary;
201 library = DlOpenLibrary(library_name);
202 if (library == NULL) {
203 ALOGE("Failed to dlopen %s: %s", library_name, DlGetError());
204 return false;
205 }
206 }
207
208 DlSymbol JNI_GetDefaultJavaVMInitArgs_ = FindSymbol(library, "JNI_GetDefaultJavaVMInitArgs");
209 if (JNI_GetDefaultJavaVMInitArgs_ == NULL) {
210 return false;
211 }
212
213 DlSymbol JNI_CreateJavaVM_ = FindSymbol(library, "JNI_CreateJavaVM");
214 if (JNI_CreateJavaVM_ == NULL) {
215 return false;
216 }
217
218 DlSymbol JNI_GetCreatedJavaVMs_ = FindSymbol(library, "JNI_GetCreatedJavaVMs");
219 if (JNI_GetCreatedJavaVMs_ == NULL) {
220 return false;
221 }
222
223 instance->jni_provider_library_name = library_name;
224 instance->jni_provider_library = library;
225 instance->JNI_GetDefaultJavaVMInitArgs = (jint (*)(void *)) JNI_GetDefaultJavaVMInitArgs_;
226 instance->JNI_CreateJavaVM = (jint (*)(JavaVM**, JNIEnv**, void*)) JNI_CreateJavaVM_;
227 instance->JNI_GetCreatedJavaVMs = (jint (*)(JavaVM**, jsize, jsize*)) JNI_GetCreatedJavaVMs_;
228
229 return true;
230 }
231
JniInvocationDestroy(struct JniInvocationImpl * instance)232 void JniInvocationDestroy(struct JniInvocationImpl* instance) {
233 DlCloseLibrary(instance->jni_provider_library);
234 memset(instance, 0, sizeof(*instance));
235 }
236