diff options
Diffstat (limited to 'libnativebridge/native_bridge.cc')
-rw-r--r-- | libnativebridge/native_bridge.cc | 143 |
1 files changed, 98 insertions, 45 deletions
diff --git a/libnativebridge/native_bridge.cc b/libnativebridge/native_bridge.cc index b24d14ade2..fb13d62be0 100644 --- a/libnativebridge/native_bridge.cc +++ b/libnativebridge/native_bridge.cc @@ -31,6 +31,10 @@ #include <android-base/macros.h> #include <log/log.h> +#ifdef ART_TARGET_ANDROID +#include "nativeloader/dlext_namespaces.h" +#endif + namespace android { #ifdef __APPLE__ @@ -40,6 +44,28 @@ void UNUSED(const T&) {} extern "C" { +void* OpenSystemLibrary(const char* path, int flags) { +#ifdef ART_TARGET_ANDROID + // The system namespace is called "default" for binaries in /system and + // "system" for those in the Runtime APEX. Try "system" first since + // "default" always exists. + // TODO(b/185587109): Get rid of this error prone logic. + android_namespace_t* system_ns = android_get_exported_namespace("system"); + if (system_ns == nullptr) { + system_ns = android_get_exported_namespace("default"); + LOG_ALWAYS_FATAL_IF(system_ns == nullptr, + "Failed to get system namespace for loading %s", path); + } + const android_dlextinfo dlextinfo = { + .flags = ANDROID_DLEXT_USE_NAMESPACE, + .library_namespace = system_ns, + }; + return android_dlopen_ext(path, flags, &dlextinfo); +#else + return dlopen(path, flags); +#endif +} + // Environment values required by the apps running with native bridge. struct NativeBridgeRuntimeValues { const char* os_arch; @@ -223,8 +249,12 @@ bool LoadNativeBridge(const char* nb_library_filename, if (!NativeBridgeNameAcceptable(nb_library_filename)) { CloseNativeBridge(true); } else { - // Try to open the library. - void* handle = dlopen(nb_library_filename, RTLD_LAZY); + // Try to open the library. We assume this library is provided by the + // platform rather than the ART APEX itself, so use the system namespace + // to avoid requiring a static linker config link to it from the + // com_android_art namespace. + void* handle = OpenSystemLibrary(nb_library_filename, RTLD_LAZY); + if (handle != nullptr) { callbacks = reinterpret_cast<NativeBridgeCallbacks*>(dlsym(handle, kNativeBridgeInterfaceSymbol)); @@ -233,13 +263,18 @@ bool LoadNativeBridge(const char* nb_library_filename, // Store the handle for later. native_bridge_handle = handle; } else { + ALOGW("Unsupported native bridge API in %s (is version %d not compatible with %d)", + nb_library_filename, callbacks->version, NAMESPACE_VERSION); callbacks = nullptr; dlclose(handle); - ALOGW("Unsupported native bridge interface."); } } else { dlclose(handle); + ALOGW("Unsupported native bridge API in %s: %s not found", + nb_library_filename, kNativeBridgeInterfaceSymbol); } + } else { + ALOGW("Failed to load native bridge implementation: %s", dlerror()); } // Two failure conditions: could not find library (dlopen failed), or could not find native @@ -263,32 +298,27 @@ bool NeedsNativeBridge(const char* instruction_set) { return strncmp(instruction_set, ABI_STRING, strlen(ABI_STRING) + 1) != 0; } -bool PreInitializeNativeBridge(const char* app_data_dir_in, const char* instruction_set) { - if (state != NativeBridgeState::kOpened) { - ALOGE("Invalid state: native bridge is expected to be opened."); - CloseNativeBridge(true); +#ifndef __APPLE__ +static bool MountCpuinfo(const char* cpuinfo_path) { + // If the file does not exist, the mount command will fail, + // so we save the extra file existence check. + if (TEMP_FAILURE_RETRY(mount(cpuinfo_path, // Source. + "/proc/cpuinfo", // Target. + nullptr, // FS type. + MS_BIND, // Mount flags: bind mount. + nullptr)) == -1) { // "Data." + ALOGW("Failed to bind-mount %s as /proc/cpuinfo: %s", cpuinfo_path, strerror(errno)); return false; } + return true; +} +#endif - if (app_data_dir_in != nullptr) { - // Create the path to the application code cache directory. - // The memory will be release after Initialization or when the native bridge is closed. - const size_t len = strlen(app_data_dir_in) + strlen(kCodeCacheDir) + 2; // '\0' + '/' - app_code_cache_dir = new char[len]; - snprintf(app_code_cache_dir, len, "%s/%s", app_data_dir_in, kCodeCacheDir); - } else { - ALOGW("Application private directory isn't available."); - app_code_cache_dir = nullptr; - } - - // Bind-mount /system/lib{,64}/<isa>/cpuinfo to /proc/cpuinfo. - // Failure is not fatal and will keep the native bridge in kPreInitialized. - state = NativeBridgeState::kPreInitialized; - -#ifndef __APPLE__ +static void MountCpuinfoForInstructionSet(const char* instruction_set) { if (instruction_set == nullptr) { - return true; + return; } + size_t isa_len = strlen(instruction_set); if (isa_len > 10) { // 10 is a loose upper bound on the currently known instruction sets (a tight bound is 7 for @@ -296,37 +326,60 @@ bool PreInitializeNativeBridge(const char* app_data_dir_in, const char* instruct // be another instruction set in the future. ALOGW("Instruction set %s is malformed, must be less than or equal to 10 characters.", instruction_set); - return true; + return; } - // If the file does not exist, the mount command will fail, - // so we save the extra file existence check. +#if defined(__APPLE__) + ALOGW("Mac OS does not support bind-mounting. Host simulation of native bridge impossible."); + +#elif !defined(__ANDROID__) + // To be able to test on the host, we hardwire a relative path. + MountCpuinfo("./cpuinfo"); + +#else // __ANDROID__ char cpuinfo_path[1024]; -#if defined(__ANDROID__) - snprintf(cpuinfo_path, sizeof(cpuinfo_path), "/system/lib" + // Bind-mount /system/etc/cpuinfo.<isa>.txt to /proc/cpuinfo. + snprintf(cpuinfo_path, sizeof(cpuinfo_path), "/system/etc/cpuinfo.%s.txt", instruction_set); + if (MountCpuinfo(cpuinfo_path)) { + return; + } + + // Bind-mount /system/lib{,64}/<isa>/cpuinfo to /proc/cpuinfo. + // TODO(b/179753190): remove when all implementations migrate to system/etc! #ifdef __LP64__ - "64" + snprintf(cpuinfo_path, sizeof(cpuinfo_path), "/system/lib64/%s/cpuinfo", instruction_set); +#else + snprintf(cpuinfo_path, sizeof(cpuinfo_path), "/system/lib/%s/cpuinfo", instruction_set); #endif // __LP64__ - "/%s/cpuinfo", instruction_set); -#else // !__ANDROID__ - // To be able to test on the host, we hardwire a relative path. - snprintf(cpuinfo_path, sizeof(cpuinfo_path), "./cpuinfo"); + MountCpuinfo(cpuinfo_path); + #endif +} - // Bind-mount. - if (TEMP_FAILURE_RETRY(mount(cpuinfo_path, // Source. - "/proc/cpuinfo", // Target. - nullptr, // FS type. - MS_BIND, // Mount flags: bind mount. - nullptr)) == -1) { // "Data." - ALOGW("Failed to bind-mount %s as /proc/cpuinfo: %s", cpuinfo_path, strerror(errno)); +bool PreInitializeNativeBridge(const char* app_data_dir_in, const char* instruction_set) { + if (state != NativeBridgeState::kOpened) { + ALOGE("Invalid state: native bridge is expected to be opened."); + CloseNativeBridge(true); + return false; + } + + if (app_data_dir_in != nullptr) { + // Create the path to the application code cache directory. + // The memory will be release after Initialization or when the native bridge is closed. + const size_t len = strlen(app_data_dir_in) + strlen(kCodeCacheDir) + 2; // '\0' + '/' + app_code_cache_dir = new char[len]; + snprintf(app_code_cache_dir, len, "%s/%s", app_data_dir_in, kCodeCacheDir); + } else { + ALOGW("Application private directory isn't available."); + app_code_cache_dir = nullptr; } -#else // __APPLE__ - UNUSED(instruction_set); - ALOGW("Mac OS does not support bind-mounting. Host simulation of native bridge impossible."); -#endif + // Mount cpuinfo that corresponds to the instruction set. + // Failure is not fatal. + MountCpuinfoForInstructionSet(instruction_set); + + state = NativeBridgeState::kPreInitialized; return true; } |