xref: /aosp_15_r20/libnativehelper/JniInvocation.c (revision 0797b24ee566c78eb48500180cb4bf71f81c8aab)
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