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