summaryrefslogtreecommitdiff
path: root/libnativebridge/native_bridge.cc
diff options
context:
space:
mode:
Diffstat (limited to 'libnativebridge/native_bridge.cc')
-rw-r--r--libnativebridge/native_bridge.cc143
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;
}