1 /* 2 * Copyright (C) 2021 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 "libnativehelper_lazy.h" 18 19 #include <dlfcn.h> 20 #include <pthread.h> 21 22 #include <stdatomic.h> 23 #include <stdbool.h> 24 25 #include "jni.h" 26 #include "log/log.h" 27 28 #include "android/file_descriptor_jni.h" 29 #include "nativehelper/JNIHelp.h" 30 #include "nativehelper/JNIPlatformHelp.h" 31 #include "nativehelper/JniInvocation.h" 32 33 // This file provides a lazy interface to libnativehelper.so to address early boot dependencies. 34 // Specifically bootanimation now runs before the ART APEX is loaded and libnativehelper.so is 35 // in the ART APEX. bootanimation does not call any code in libnativehelper. 36 37 // Method pointers to libnativehelper methods are held in array which simplifies checking 38 // all pointers are initialized. 39 enum MethodIndex { 40 // NDK file descriptor API in file_descriptor_jni.h. 41 k_AFileDescriptor_create, 42 k_AFileDescriptor_getFd, 43 k_AFileDescriptor_setFd, 44 45 // JNI_Invocation API declared in jni.h. 46 k_JNI_CreateJavaVM, 47 k_JNI_GetCreatedJavaVMs, 48 k_JNI_GetDefaultJavaVMInitArgs, 49 50 // Methods in JNIPlatformHelp.h. 51 k_jniGetNioBufferBaseArray, 52 k_jniGetNioBufferBaseArrayOffset, 53 k_jniGetNioBufferFields, 54 k_jniGetNioBufferPointer, 55 k_jniUninitializeConstants, 56 57 // Methods in JniInvocation.h. 58 k_JniInvocationCreate, 59 k_JniInvocationDestroy, 60 k_JniInvocationGetLibrary, 61 k_JniInvocationInit, 62 63 // Marker for count of methods 64 k_MethodCount 65 }; 66 67 // Table of methods pointers in libnativehelper APIs. 68 static void* g_Methods[k_MethodCount]; 69 70 // 71 // Libnativehelper lazy loading. 72 // 73 74 static atomic_bool gPreventLibnativehelperLoading = false; // Allows tests to block loading. 75 76 void PreventLibnativehelperLazyLoadingForTests() { 77 atomic_store_explicit(&gPreventLibnativehelperLoading, true, memory_order_release); 78 } 79 80 static void* LoadLibnativehelper(int dlopen_flags) { 81 if (atomic_load_explicit(&gPreventLibnativehelperLoading, memory_order_acquire)) { 82 return NULL; 83 } 84 return dlopen("libnativehelper.so", dlopen_flags); 85 } 86 87 static bool IsLibnativehelperLoaded() { 88 return LoadLibnativehelper(RTLD_NOLOAD) != NULL; 89 } 90 91 // 92 // Initialization and symbol binding. 93 // 94 95 static void BindSymbol(void* handle, const char* name, enum MethodIndex index) { 96 void* symbol = dlsym(handle, name); 97 LOG_ALWAYS_FATAL_IF(symbol == NULL, 98 "Failed to find symbol '%s' in libnativehelper.so: %s", name, dlerror()); 99 g_Methods[index] = symbol; 100 } 101 102 static void InitializeOnce() { 103 void* handle = LoadLibnativehelper(RTLD_NOW); 104 LOG_ALWAYS_FATAL_IF(handle == NULL, "Failed to load libnativehelper.so: %s", dlerror()); 105 106 #undef BIND_SYMBOL 107 #define BIND_SYMBOL(name) BindSymbol(handle, #name, k_ ## name); 108 109 // NDK file descriptor API in file_descriptor_jni.h. 110 BIND_SYMBOL(AFileDescriptor_create); 111 BIND_SYMBOL(AFileDescriptor_getFd); 112 BIND_SYMBOL(AFileDescriptor_setFd); 113 114 // JNI_Invocation API declared in jni.h. 115 BIND_SYMBOL(JNI_CreateJavaVM); 116 BIND_SYMBOL(JNI_GetCreatedJavaVMs); 117 BIND_SYMBOL(JNI_GetDefaultJavaVMInitArgs); 118 119 // Methods in JNIPlatformHelp.h. 120 BIND_SYMBOL(jniGetNioBufferBaseArray); 121 BIND_SYMBOL(jniGetNioBufferBaseArrayOffset); 122 BIND_SYMBOL(jniGetNioBufferFields); 123 BIND_SYMBOL(jniGetNioBufferPointer); 124 BIND_SYMBOL(jniUninitializeConstants); 125 126 // Methods in JniInvocation.h. 127 BIND_SYMBOL(JniInvocationCreate); 128 BIND_SYMBOL(JniInvocationDestroy); 129 BIND_SYMBOL(JniInvocationGetLibrary); 130 BIND_SYMBOL(JniInvocationInit); 131 132 #undef BIND_SYMBOL 133 134 // Check every symbol is bound. 135 for (int i = 0; i < k_MethodCount; ++i) { 136 LOG_ALWAYS_FATAL_IF(g_Methods[i] == NULL, 137 "Uninitialized method in libnativehelper_lazy at index: %d", i); 138 } 139 } 140 141 static void EnsureInitialized() { 142 static pthread_once_t initialized = PTHREAD_ONCE_INIT; 143 pthread_once(&initialized, InitializeOnce); 144 } 145 146 #define INVOKE_METHOD(name, method_type, args...) \ 147 do { \ 148 EnsureInitialized(); \ 149 void* method = g_Methods[k_ ## name]; \ 150 return ((method_type) method)(args); \ 151 } while (0) 152 153 #define INVOKE_VOID_METHOD(name, method_type, args...) \ 154 do { \ 155 EnsureInitialized(); \ 156 void* method = g_Methods[k_ ## name]; \ 157 ((method_type) method)(args); \ 158 } while (0) 159 160 // 161 // Forwarding for methods in file_descriptor_jni.h. 162 // 163 164 jobject AFileDescriptor_create(JNIEnv* env) { 165 typedef jobject (*M)(JNIEnv*); 166 INVOKE_METHOD(AFileDescriptor_create, M, env); 167 } 168 169 int AFileDescriptor_getFd(JNIEnv* env, jobject fileDescriptor) { 170 typedef int (*M)(JNIEnv*, jobject); 171 INVOKE_METHOD(AFileDescriptor_getFd, M, env, fileDescriptor); 172 } 173 174 void AFileDescriptor_setFd(JNIEnv* env, jobject fileDescriptor, int fd) { 175 typedef void (*M)(JNIEnv*, jobject, int); 176 INVOKE_VOID_METHOD(AFileDescriptor_setFd, M, env, fileDescriptor, fd); 177 } 178 179 // 180 // Forwarding for the JNI_Invocation API declarded in jni.h. 181 // 182 183 // Some code may attempt to use this JNI_Invocation API to establish if there is a VM (b/174768641). 184 // Because INVOKE_METHOD produces a fatal error if used before libnativehelper.so, we need some 185 // additional logic for the JNI_Invocation API to allow JNI_GetCreatedJavaVMs to be called even 186 // if libnativehelper.so is not loaded. 187 // 188 // Consequently, we use an atomic variable if a VM is created through this API. But note 189 // this is not the only way a JavaVM may be created so checking this flag alone is not enough. 190 static atomic_bool gJavaVmCreatedLazily = false; 191 192 static jint JNI_CreateJavaVMImpl(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) { 193 typedef jint (*M)(JavaVM**, JNIEnv**, void*); 194 INVOKE_METHOD(JNI_CreateJavaVM, M, p_vm, p_env, vm_args); 195 } 196 197 jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) { 198 jint status = JNI_CreateJavaVMImpl(p_vm, p_env, vm_args); 199 if (status == JNI_OK) { 200 atomic_store_explicit(&gJavaVmCreatedLazily, true, memory_order_release); 201 } 202 return status; 203 } 204 205 jint JNI_GetDefaultJavaVMInitArgs(void* vm_args) { 206 typedef jint (*M)(void*); 207 INVOKE_METHOD(JNI_GetDefaultJavaVMInitArgs, M, vm_args); 208 } 209 210 jint JNI_GetCreatedJavaVMs(JavaVM** p_vm, jsize vm_max, jsize* p_vm_count) { 211 typedef jint (*M)(JavaVM**, jsize, jsize*); 212 // If no VMs have been created created lazily and libnativehelper.so has not been loaded 213 // by other means, then fill-in the VM count as zero and return JNI_OK. 214 if (!atomic_load_explicit(&gJavaVmCreatedLazily, memory_order_acquire) && 215 !IsLibnativehelperLoaded()) { 216 *p_vm_count = 0; 217 return JNI_OK; 218 } 219 INVOKE_METHOD(JNI_GetCreatedJavaVMs, M, p_vm, vm_max, p_vm_count); 220 } 221 222 // 223 // Forwarding for methods in JNIPlatformHelp.h. 224 // 225 226 jarray jniGetNioBufferBaseArray(JNIEnv* env, jobject nioBuffer) { 227 typedef jarray (*M)(JNIEnv*, jobject); 228 INVOKE_METHOD(jniGetNioBufferBaseArray, M, env, nioBuffer); 229 } 230 231 int jniGetNioBufferBaseArrayOffset(JNIEnv* env, jobject nioBuffer) { 232 typedef int (*M)(JNIEnv*, jobject); 233 INVOKE_METHOD(jniGetNioBufferBaseArrayOffset, M, env, nioBuffer); 234 } 235 236 jlong jniGetNioBufferFields(JNIEnv* env, jobject nioBuffer, 237 jint* position, jint* limit, jint* elementSizeShift) { 238 typedef jlong (*M)(JNIEnv*, jobject, jint*, jint*, jint*); 239 INVOKE_METHOD(jniGetNioBufferFields, M, env, nioBuffer, position, limit, 240 elementSizeShift); 241 } 242 243 jlong jniGetNioBufferPointer(JNIEnv* env, jobject nioBuffer) { 244 typedef jlong (*M)(JNIEnv*, jobject); 245 INVOKE_METHOD(jniGetNioBufferPointer, M, env, nioBuffer); 246 } 247 248 void jniUninitializeConstants() { 249 typedef void (*M)(); 250 INVOKE_VOID_METHOD(jniUninitializeConstants, M); 251 } 252 253 // 254 // Forwarding for methods in JniInvocation.h. 255 // 256 257 struct JniInvocationImpl* JniInvocationCreate() { 258 typedef struct JniInvocationImpl* (*M)(); 259 INVOKE_METHOD(JniInvocationCreate, M); 260 } 261 262 void JniInvocationDestroy(struct JniInvocationImpl* instance) { 263 typedef void (*M)(struct JniInvocationImpl*); 264 INVOKE_METHOD(JniInvocationDestroy, M, instance); 265 } 266 267 bool JniInvocationInit(struct JniInvocationImpl* instance, const char* library) { 268 typedef bool (*M)(struct JniInvocationImpl*, const char*); 269 INVOKE_METHOD(JniInvocationInit, M, instance, library); 270 } 271 272 const char* JniInvocationGetLibrary(const char* library, char* buffer) { 273 typedef const char* (*M)(const char*, char*); 274 INVOKE_METHOD(JniInvocationGetLibrary, M, library, buffer); 275 } 276