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