Merge "radio: fix compatibility for 64 bit processes"
diff --git a/adb/adb_trace.cpp b/adb/adb_trace.cpp
index 369dec9..002d061 100644
--- a/adb/adb_trace.cpp
+++ b/adb/adb_trace.cpp
@@ -155,7 +155,24 @@
}
#endif
+#if !defined(_WIN32)
+ // adb historically ignored $ANDROID_LOG_TAGS but passed it through to logcat.
+ // If set, move it out of the way so that libbase logging doesn't try to parse it.
+ std::string log_tags;
+ char* ANDROID_LOG_TAGS = getenv("ANDROID_LOG_TAGS");
+ if (ANDROID_LOG_TAGS) {
+ log_tags = ANDROID_LOG_TAGS;
+ unsetenv("ANDROID_LOG_TAGS");
+ }
+#endif
+
android::base::InitLogging(argv, &AdbLogger);
+
+#if !defined(_WIN32)
+ // Put $ANDROID_LOG_TAGS back so we can pass it to logcat.
+ if (!log_tags.empty()) setenv("ANDROID_LOG_TAGS", log_tags.c_str(), 1);
+#endif
+
setup_trace_mask();
VLOG(ADB) << adb_version();
diff --git a/adb/bugreport.cpp b/adb/bugreport.cpp
index c348dd5..9b59d05 100644
--- a/adb/bugreport.cpp
+++ b/adb/bugreport.cpp
@@ -237,8 +237,7 @@
// Uses a default value until device provides the proper name
dest_file = "bugreport.zip";
} else {
- if (!android::base::EndsWith(dest_file, ".zip")) {
- // TODO: use a case-insensitive comparison (like EndsWithIgnoreCase
+ if (!android::base::EndsWithIgnoreCase(dest_file, ".zip")) {
dest_file += ".zip";
}
}
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index fe5d280..1f03c1a 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -1983,20 +1983,15 @@
static int install_app(TransportType transport, const char* serial, int argc, const char** argv) {
// The last argument must be the APK file
const char* file = argv[argc - 1];
- const char* dot = strrchr(file, '.');
- bool found_apk = false;
- struct stat sb;
- if (dot && !strcasecmp(dot, ".apk")) {
- if (stat(file, &sb) == -1 || !S_ISREG(sb.st_mode)) {
- fprintf(stderr, "Invalid APK file: %s\n", file);
- return EXIT_FAILURE;
- }
- found_apk = true;
+ if (!android::base::EndsWithIgnoreCase(file, ".apk")) {
+ fprintf(stderr, "Filename doesn't end .apk: %s\n", file);
+ return EXIT_FAILURE;
}
- if (!found_apk) {
- fprintf(stderr, "Missing APK file\n");
- return EXIT_FAILURE;
+ struct stat sb;
+ if (stat(file, &sb) == -1) {
+ fprintf(stderr, "Failed to stat %s: %s\n", file, strerror(errno));
+ return 1;
}
int localFd = adb_open(file, O_RDONLY);
@@ -2042,22 +2037,16 @@
static int install_multiple_app(TransportType transport, const char* serial, int argc,
const char** argv)
{
- int i;
- struct stat sb;
- uint64_t total_size = 0;
// Find all APK arguments starting at end.
// All other arguments passed through verbatim.
int first_apk = -1;
- for (i = argc - 1; i >= 0; i--) {
+ uint64_t total_size = 0;
+ for (int i = argc - 1; i >= 0; i--) {
const char* file = argv[i];
- const char* dot = strrchr(file, '.');
- if (dot && !strcasecmp(dot, ".apk")) {
- if (stat(file, &sb) == -1 || !S_ISREG(sb.st_mode)) {
- fprintf(stderr, "Invalid APK file: %s\n", file);
- return EXIT_FAILURE;
- }
- total_size += sb.st_size;
+ if (android::base::EndsWithIgnoreCase(file, ".apk")) {
+ struct stat sb;
+ if (stat(file, &sb) != -1) total_size += sb.st_size;
first_apk = i;
} else {
break;
@@ -2065,7 +2054,7 @@
}
if (first_apk == -1) {
- fprintf(stderr, "Missing APK file\n");
+ fprintf(stderr, "No APK file on command line\n");
return 1;
}
@@ -2077,7 +2066,7 @@
}
std::string cmd = android::base::StringPrintf("%s install-create -S %" PRIu64, install_cmd.c_str(), total_size);
- for (i = 1; i < first_apk; i++) {
+ for (int i = 1; i < first_apk; i++) {
cmd += " " + escape_arg(argv[i]);
}
@@ -2109,10 +2098,11 @@
// Valid session, now stream the APKs
int success = 1;
- for (i = first_apk; i < argc; i++) {
+ for (int i = first_apk; i < argc; i++) {
const char* file = argv[i];
+ struct stat sb;
if (stat(file, &sb) == -1) {
- fprintf(stderr, "Failed to stat %s\n", file);
+ fprintf(stderr, "Failed to stat %s: %s\n", file, strerror(errno));
success = 0;
goto finalize_session;
}
@@ -2212,10 +2202,8 @@
static const char *const DATA_DEST = "/data/local/tmp/%s";
static const char *const SD_DEST = "/sdcard/tmp/%s";
const char* where = DATA_DEST;
- int i;
- struct stat sb;
- for (i = 1; i < argc; i++) {
+ for (int i = 1; i < argc; i++) {
if (!strcmp(argv[i], "-s")) {
where = SD_DEST;
}
@@ -2224,22 +2212,15 @@
// Find last APK argument.
// All other arguments passed through verbatim.
int last_apk = -1;
- for (i = argc - 1; i >= 0; i--) {
- const char* file = argv[i];
- const char* dot = strrchr(file, '.');
- if (dot && !strcasecmp(dot, ".apk")) {
- if (stat(file, &sb) == -1 || !S_ISREG(sb.st_mode)) {
- fprintf(stderr, "Invalid APK file: %s\n", file);
- return EXIT_FAILURE;
- }
-
+ for (int i = argc - 1; i >= 0; i--) {
+ if (android::base::EndsWithIgnoreCase(argv[i], ".apk")) {
last_apk = i;
break;
}
}
if (last_apk == -1) {
- fprintf(stderr, "Missing APK file\n");
+ fprintf(stderr, "No APK file on command line\n");
return EXIT_FAILURE;
}
diff --git a/fs_mgr/fs_mgr_verity.cpp b/fs_mgr/fs_mgr_verity.cpp
index 7fe6763..031b042 100644
--- a/fs_mgr/fs_mgr_verity.cpp
+++ b/fs_mgr/fs_mgr_verity.cpp
@@ -341,6 +341,17 @@
return 0;
}
+static int test_access(char *device) {
+ int tries = 25;
+ while (tries--) {
+ if (!access(device, F_OK) || errno != ENOENT) {
+ return 0;
+ }
+ usleep(40 * 1000);
+ }
+ return -1;
+}
+
static int check_verity_restart(const char *fname)
{
char buffer[VERITY_KMSG_BUFSIZE + 1];
@@ -1031,6 +1042,11 @@
fstab->blk_device = verity_blk_name;
verity_blk_name = 0;
+ // make sure we've set everything up properly
+ if (test_access(fstab->blk_device) < 0) {
+ goto out;
+ }
+
retval = FS_MGR_SETUP_VERITY_SUCCESS;
out:
diff --git a/healthd/healthd.cpp b/healthd/healthd.cpp
index 3f0e047..aa6735d 100644
--- a/healthd/healthd.cpp
+++ b/healthd/healthd.cpp
@@ -297,12 +297,18 @@
}
static void healthd_mainloop(void) {
+ int nevents = 0;
while (1) {
struct epoll_event events[eventct];
- int nevents;
int timeout = awake_poll_interval;
int mode_timeout;
+ /* Don't wait for first timer timeout to run periodic chores */
+ if (!nevents)
+ periodic_chores();
+
+ healthd_mode_ops->heartbeat();
+
mode_timeout = healthd_mode_ops->preparetowait();
if (timeout < 0 || (mode_timeout > 0 && mode_timeout < timeout))
timeout = mode_timeout;
@@ -318,11 +324,6 @@
if (events[n].data.ptr)
(*(void (*)(int))events[n].data.ptr)(events[n].events);
}
-
- if (!nevents)
- periodic_chores();
-
- healthd_mode_ops->heartbeat();
}
return;
diff --git a/include/nativebridge/native_bridge.h b/include/nativebridge/native_bridge.h
index 18300bc..26556f0 100644
--- a/include/nativebridge/native_bridge.h
+++ b/include/nativebridge/native_bridge.h
@@ -62,12 +62,19 @@
bool NativeBridgeInitialized();
// Load a shared library that is supported by the native bridge.
+//
+// Starting with v3, NativeBridge has two scenarios: with/without namespace.
+// Use NativeBridgeLoadLibraryExt() instead in namespace scenario.
void* NativeBridgeLoadLibrary(const char* libpath, int flag);
// Get a native bridge trampoline for specified native method.
void* NativeBridgeGetTrampoline(void* handle, const char* name, const char* shorty, uint32_t len);
-// True if native library is valid and is for an ABI that is supported by native bridge.
+// True if native library paths are valid and is for an ABI that is supported by native bridge.
+// The *libpath* must point to a library.
+//
+// Starting with v3, NativeBridge has two scenarios: with/without namespace.
+// Use NativeBridgeIsPathSupported() instead in namespace scenario.
bool NativeBridgeIsSupported(const char* libpath);
// Returns the version number of the native bridge. This information is available after a
@@ -91,6 +98,48 @@
// This functionality is exposed mainly for testing.
bool NativeBridgeNameAcceptable(const char* native_bridge_library_filename);
+// Decrements the reference count on the dynamic library handler. If the reference count drops
+// to zero then the dynamic library is unloaded.
+int NativeBridgeUnloadLibrary(void* handle);
+
+// Get last error message of native bridge when fail to load library or search symbol.
+// This is reflection of dlerror() for native bridge.
+char* NativeBridgeGetError();
+
+struct native_bridge_namespace_t;
+
+// True if native library paths are valid and is for an ABI that is supported by native bridge.
+// Different from NativeBridgeIsSupported(), the *path* here must be a directory containing
+// libraries of an ABI.
+//
+// Starting with v3, NativeBridge has two scenarios: with/without namespace.
+// Use NativeBridgeIsSupported() instead in non-namespace scenario.
+bool NativeBridgeIsPathSupported(const char* path);
+
+// Initializes public and anonymous namespace at native bridge side.
+//
+// Starting with v3, NativeBridge has two scenarios: with/without namespace.
+// Should not use in non-namespace scenario.
+bool NativeBridgeInitNamespace(const char* public_ns_sonames,
+ const char* anon_ns_library_path);
+
+// Create a namespace and pass the key of related namespaces to native bridge.
+//
+// Starting with v3, NativeBridge has two scenarios: with/without namespace.
+// Should not use in non-namespace scenario.
+native_bridge_namespace_t* NativeBridgeCreateNamespace(const char* name,
+ const char* ld_library_path,
+ const char* default_library_path,
+ uint64_t type,
+ const char* permitted_when_isolated_path,
+ native_bridge_namespace_t* parent_ns);
+
+// Load a shared library with namespace key that is supported by the native bridge.
+//
+// Starting with v3, NativeBridge has two scenarios: with/without namespace.
+// Use NativeBridgeLoadLibrary() instead in non-namespace scenario.
+void* NativeBridgeLoadLibraryExt(const char* libpath, int flag, native_bridge_namespace_t* ns);
+
// Native bridge interfaces to runtime.
struct NativeBridgeCallbacks {
// Version number of the interface.
@@ -114,6 +163,9 @@
// flag [IN] the stardard RTLD_XXX defined in bionic dlfcn.h
// Returns:
// The opaque handle of the shared library if sucessful, otherwise NULL
+ //
+ // Starting with v3, NativeBridge has two scenarios: with/without namespace.
+ // Use loadLibraryExt instead in namespace scenario.
void* (*loadLibrary)(const char* libpath, int flag);
// Get a native bridge trampoline for specified native method. The trampoline has same
@@ -133,6 +185,9 @@
// libpath [IN] path to the shared library
// Returns:
// TRUE if library is supported by native bridge, FALSE otherwise
+ //
+ // Starting with v3, NativeBridge has two scenarios: with/without namespace.
+ // Use isPathSupported instead in namespace scenario.
bool (*isSupported)(const char* libpath);
// Provide environment values required by the app running with native bridge according to the
@@ -169,6 +224,88 @@
// runtime.
// Otherwise, a pointer to the signal handler.
NativeBridgeSignalHandlerFn (*getSignalHandler)(int signal);
+
+ // Added callbacks in version 3.
+
+ // Decrements the reference count on the dynamic library handler. If the reference count drops
+ // to zero then the dynamic library is unloaded.
+ //
+ // Parameters:
+ // handle [IN] the handler of a dynamic library.
+ //
+ // Returns:
+ // 0 on success, and nonzero on error.
+ int (*unloadLibrary)(void* handle);
+
+ // Dump the last failure message of native bridge when fail to load library or search symbol.
+ //
+ // Parameters:
+ //
+ // Returns:
+ // A string describing the most recent error that occurred when load library
+ // or lookup symbol via native bridge.
+ char* (*getError)();
+
+ // Check whether library paths are supported by native bridge.
+ //
+ // Parameters:
+ // library_path [IN] search paths for native libraries (directories separated by ':')
+ // Returns:
+ // TRUE if libraries within search paths are supported by native bridge, FALSE otherwise
+ //
+ // Starting with v3, NativeBridge has two scenarios: with/without namespace.
+ // Use isSupported instead in non-namespace scenario.
+ bool (*isPathSupported)(const char* library_path);
+
+ // Initializes anonymous namespace at native bridge side and pass the key of
+ // two namespaces(default and anonymous) owned by dynamic linker to native bridge.
+ //
+ // Parameters:
+ // public_ns_sonames [IN] the name of "public" libraries.
+ // anon_ns_library_path [IN] the library search path of (anonymous) namespace.
+ // Returns:
+ // true if the pass is ok.
+ // Otherwise, false.
+ //
+ // Starting with v3, NativeBridge has two scenarios: with/without namespace.
+ // Should not use in non-namespace scenario.
+ bool (*initNamespace)(const char* public_ns_sonames,
+ const char* anon_ns_library_path);
+
+
+ // Create a namespace and pass the key of releated namespaces to native bridge.
+ //
+ // Parameters:
+ // name [IN] the name of the namespace.
+ // ld_library_path [IN] the first set of library search paths of the namespace.
+ // default_library_path [IN] the second set of library search path of the namespace.
+ // type [IN] the attribute of the namespace.
+ // permitted_when_isolated_path [IN] the permitted path for isolated namespace(if it is).
+ // parent_ns [IN] the pointer of the parent namespace to be inherited from.
+ // Returns:
+ // native_bridge_namespace_t* for created namespace or nullptr in the case of error.
+ //
+ // Starting with v3, NativeBridge has two scenarios: with/without namespace.
+ // Should not use in non-namespace scenario.
+ native_bridge_namespace_t* (*createNamespace)(const char* name,
+ const char* ld_library_path,
+ const char* default_library_path,
+ uint64_t type,
+ const char* permitted_when_isolated_path,
+ native_bridge_namespace_t* parent_ns);
+
+ // Load a shared library within a namespace.
+ //
+ // Parameters:
+ // libpath [IN] path to the shared library
+ // flag [IN] the stardard RTLD_XXX defined in bionic dlfcn.h
+ // ns [IN] the pointer of the namespace in which the library should be loaded.
+ // Returns:
+ // The opaque handle of the shared library if sucessful, otherwise NULL
+ //
+ // Starting with v3, NativeBridge has two scenarios: with/without namespace.
+ // Use loadLibrary instead in non-namespace scenario.
+ void* (*loadLibraryExt)(const char* libpath, int flag, native_bridge_namespace_t* ns);
};
// Runtime interfaces to native bridge.
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 1e569af..e7176c6 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -141,23 +141,24 @@
}
}
-static bool is_legal_property_name(const char* name, size_t namelen)
+bool is_legal_property_name(const std::string &name)
{
- size_t i;
+ size_t namelen = name.size();
+
if (namelen >= PROP_NAME_MAX) return false;
if (namelen < 1) return false;
if (name[0] == '.') return false;
if (name[namelen - 1] == '.') return false;
- /* Only allow alphanumeric, plus '.', '-', or '_' */
+ /* Only allow alphanumeric, plus '.', '-', '@', or '_' */
/* Don't allow ".." to appear in a property name */
- for (i = 0; i < namelen; i++) {
+ for (size_t i = 0; i < namelen; i++) {
if (name[i] == '.') {
// i=0 is guaranteed to never have a dot. See above.
if (name[i-1] == '.') return false;
continue;
}
- if (name[i] == '_' || name[i] == '-') continue;
+ if (name[i] == '_' || name[i] == '-' || name[i] == '@') continue;
if (name[i] >= 'a' && name[i] <= 'z') continue;
if (name[i] >= 'A' && name[i] <= 'Z') continue;
if (name[i] >= '0' && name[i] <= '9') continue;
@@ -168,10 +169,9 @@
}
static int property_set_impl(const char* name, const char* value) {
- size_t namelen = strlen(name);
size_t valuelen = strlen(value);
- if (!is_legal_property_name(name, namelen)) return -1;
+ if (!is_legal_property_name(name)) return -1;
if (valuelen >= PROP_VALUE_MAX) return -1;
if (strcmp("selinux.restorecon_recursive", name) == 0 && valuelen > 0) {
@@ -188,7 +188,7 @@
__system_property_update(pi, value, valuelen);
} else {
- int rc = __system_property_add(name, namelen, value, valuelen);
+ int rc = __system_property_add(name, strlen(name), value, valuelen);
if (rc < 0) {
return rc;
}
@@ -272,7 +272,7 @@
msg.name[PROP_NAME_MAX-1] = 0;
msg.value[PROP_VALUE_MAX-1] = 0;
- if (!is_legal_property_name(msg.name, strlen(msg.name))) {
+ if (!is_legal_property_name(msg.name)) {
LOG(ERROR) << "sys_prop: illegal property name \"" << msg.name << "\"";
close(s);
return;
diff --git a/init/property_service.h b/init/property_service.h
index dbaed34..e3a2acb 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -34,6 +34,7 @@
extern void start_property_service(void);
std::string property_get(const char* name);
extern int property_set(const char *name, const char *value);
+extern bool is_legal_property_name(const std::string &name);
#endif /* _INIT_PROPERTY_H */
diff --git a/init/service.cpp b/init/service.cpp
index 685befd..6460e71 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -996,13 +996,5 @@
}
bool ServiceParser::IsValidName(const std::string& name) const {
- if (name.size() > PROP_NAME_MAX - sizeof("init.svc.")) {
- return false;
- }
- for (const auto& c : name) {
- if (!isalnum(c) && (c != '_') && (c != '-')) {
- return false;
- }
- }
- return true;
+ return is_legal_property_name("init.svc." + name);
}
diff --git a/libbacktrace/BacktraceOffline.cpp b/libbacktrace/BacktraceOffline.cpp
index c2b68bc..a05a6d8 100644
--- a/libbacktrace/BacktraceOffline.cpp
+++ b/libbacktrace/BacktraceOffline.cpp
@@ -719,7 +719,7 @@
auto binary_or_err = llvm::object::createBinary(buffer_or_err.get()->getMemBufferRef());
if (!binary_or_err) {
BACK_LOGW("failed to create binary for %s in %s: %s", elf_file.c_str(), apk_file.c_str(),
- binary_or_err.getError().message().c_str());
+ llvm::toString(binary_or_err.takeError()).c_str());
return nothing;
}
return llvm::object::OwningBinary<llvm::object::Binary>(std::move(binary_or_err.get()),
diff --git a/liblog/log_is_loggable.c b/liblog/log_is_loggable.c
index 132d96f..dda09e0 100644
--- a/liblog/log_is_loggable.c
+++ b/liblog/log_is_loggable.c
@@ -23,8 +23,6 @@
#include <sys/_system_properties.h>
#include <unistd.h>
-#include <android/log.h>
-#include <log/logger.h>
#include <private/android_logger.h>
#include "log_portability.h"
diff --git a/libnativebridge/native_bridge.cc b/libnativebridge/native_bridge.cc
index 32b2d27..43e6c0a 100644
--- a/libnativebridge/native_bridge.cc
+++ b/libnativebridge/native_bridge.cc
@@ -80,6 +80,19 @@
// Current state of the native bridge.
static NativeBridgeState state = NativeBridgeState::kNotSetup;
+// The version of NativeBridge implementation.
+// Different Nativebridge interface needs the service of different version of
+// Nativebridge implementation.
+// Used by isCompatibleWith() which is introduced in v2.
+enum NativeBridgeImplementationVersion {
+ // first version, not used.
+ DEFAULT_VERSION = 1,
+ // The version which signal semantic is introduced.
+ SIGNAL_VERSION = 2,
+ // The version which namespace semantic is introduced.
+ NAMESPACE_VERSION = 3,
+};
+
// Whether we had an error at some point.
static bool had_error = false;
@@ -100,8 +113,6 @@
// and hard code the directory name again here.
static constexpr const char* kCodeCacheDir = "code_cache";
-static constexpr uint32_t kLibNativeBridgeVersion = 2;
-
// Characters allowed in a native bridge filename. The first character must
// be in [a-zA-Z] (expected 'l' for "libx"). The rest must be in [a-zA-Z0-9._-].
static bool CharacterAllowed(char c, bool first) {
@@ -152,19 +163,18 @@
}
}
-static bool VersionCheck(const NativeBridgeCallbacks* cb) {
+// The policy of invoking Nativebridge changed in v3 with/without namespace.
+// Suggest Nativebridge implementation not maintain backward-compatible.
+static bool isCompatibleWith(const uint32_t version) {
// Libnativebridge is now designed to be forward-compatible. So only "0" is an unsupported
// version.
- if (cb == nullptr || cb->version == 0) {
+ if (callbacks == nullptr || callbacks->version == 0 || version == 0) {
return false;
}
// If this is a v2+ bridge, it may not be forwards- or backwards-compatible. Check.
- if (cb->version >= 2) {
- if (!callbacks->isCompatibleWith(kLibNativeBridgeVersion)) {
- // TODO: Scan which version is supported, and fall back to handle it.
- return false;
- }
+ if (callbacks->version >= SIGNAL_VERSION) {
+ return callbacks->isCompatibleWith(version);
}
return true;
@@ -205,7 +215,7 @@
callbacks = reinterpret_cast<NativeBridgeCallbacks*>(dlsym(handle,
kNativeBridgeInterfaceSymbol));
if (callbacks != nullptr) {
- if (VersionCheck(callbacks)) {
+ if (isCompatibleWith(NAMESPACE_VERSION)) {
// Store the handle for later.
native_bridge_handle = handle;
} else {
@@ -520,8 +530,91 @@
}
NativeBridgeSignalHandlerFn NativeBridgeGetSignalHandler(int signal) {
- if (NativeBridgeInitialized() && callbacks->version >= 2) {
- return callbacks->getSignalHandler(signal);
+ if (NativeBridgeInitialized()) {
+ if (isCompatibleWith(SIGNAL_VERSION)) {
+ return callbacks->getSignalHandler(signal);
+ } else {
+ ALOGE("not compatible with version %d, cannot get signal handler", SIGNAL_VERSION);
+ }
+ }
+ return nullptr;
+}
+
+int NativeBridgeUnloadLibrary(void* handle) {
+ if (NativeBridgeInitialized()) {
+ if (isCompatibleWith(NAMESPACE_VERSION)) {
+ return callbacks->unloadLibrary(handle);
+ } else {
+ ALOGE("not compatible with version %d, cannot unload library", NAMESPACE_VERSION);
+ }
+ }
+ return -1;
+}
+
+char* NativeBridgeGetError() {
+ if (NativeBridgeInitialized()) {
+ if (isCompatibleWith(NAMESPACE_VERSION)) {
+ return callbacks->getError();
+ } else {
+ ALOGE("not compatible with version %d, cannot get message", NAMESPACE_VERSION);
+ }
+ }
+ return nullptr;
+}
+
+bool NativeBridgeIsPathSupported(const char* path) {
+ if (NativeBridgeInitialized()) {
+ if (isCompatibleWith(NAMESPACE_VERSION)) {
+ return callbacks->isPathSupported(path);
+ } else {
+ ALOGE("not compatible with version %d, cannot check via library path", NAMESPACE_VERSION);
+ }
+ }
+ return false;
+}
+
+bool NativeBridgeInitNamespace(const char* public_ns_sonames,
+ const char* anon_ns_library_path) {
+ if (NativeBridgeInitialized()) {
+ if (isCompatibleWith(NAMESPACE_VERSION)) {
+ return callbacks->initNamespace(public_ns_sonames, anon_ns_library_path);
+ } else {
+ ALOGE("not compatible with version %d, cannot init namespace", NAMESPACE_VERSION);
+ }
+ }
+
+ return false;
+}
+
+native_bridge_namespace_t* NativeBridgeCreateNamespace(const char* name,
+ const char* ld_library_path,
+ const char* default_library_path,
+ uint64_t type,
+ const char* permitted_when_isolated_path,
+ native_bridge_namespace_t* parent_ns) {
+ if (NativeBridgeInitialized()) {
+ if (isCompatibleWith(NAMESPACE_VERSION)) {
+ return callbacks->createNamespace(name,
+ ld_library_path,
+ default_library_path,
+ type,
+ permitted_when_isolated_path,
+ parent_ns);
+ } else {
+ ALOGE("not compatible with version %d, cannot create namespace %s", NAMESPACE_VERSION, name);
+ }
+ }
+
+ return nullptr;
+}
+
+void* NativeBridgeLoadLibraryExt(const char* libpath, int flag, native_bridge_namespace_t* ns) {
+ if (NativeBridgeInitialized()) {
+ if (isCompatibleWith(NAMESPACE_VERSION)) {
+ return callbacks->loadLibraryExt(libpath, flag, ns);
+ } else {
+ ALOGE("not compatible with version %d, cannot load library in namespace", NAMESPACE_VERSION);
+ }
}
return nullptr;
}
diff --git a/libnativebridge/tests/Android.mk b/libnativebridge/tests/Android.mk
index 5ad1569..4c3e862 100644
--- a/libnativebridge/tests/Android.mk
+++ b/libnativebridge/tests/Android.mk
@@ -20,7 +20,13 @@
PreInitializeNativeBridgeFail2_test.cpp \
ReSetupNativeBridge_test.cpp \
UnavailableNativeBridge_test.cpp \
- ValidNameNativeBridge_test.cpp
+ ValidNameNativeBridge_test.cpp \
+ NativeBridge3UnloadLibrary_test.cpp \
+ NativeBridge3GetError_test.cpp \
+ NativeBridge3IsPathSupported_test.cpp \
+ NativeBridge3InitNamespace_test.cpp \
+ NativeBridge3CreateNamespace_test.cpp \
+ NativeBridge3LoadLibraryExt_test.cpp
shared_libraries := \
diff --git a/libnativebridge/tests/Android.nativebridge-dummy.mk b/libnativebridge/tests/Android.nativebridge-dummy.mk
index e556f80..2d78be0 100644
--- a/libnativebridge/tests/Android.nativebridge-dummy.mk
+++ b/libnativebridge/tests/Android.nativebridge-dummy.mk
@@ -68,3 +68,41 @@
LOCAL_MULTILIB := both
include $(BUILD_HOST_SHARED_LIBRARY)
+
+
+# v3.
+
+NATIVE_BRIDGE3_COMMON_SRC_FILES := \
+ DummyNativeBridge3.cpp
+
+# Shared library for target
+# ========================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= libnativebridge3-dummy
+
+LOCAL_SRC_FILES:= $(NATIVE_BRIDGE3_COMMON_SRC_FILES)
+LOCAL_CLANG := true
+LOCAL_CFLAGS += -Werror -Wall
+LOCAL_CPPFLAGS := -std=gnu++11 -fvisibility=protected
+LOCAL_LDFLAGS := -ldl
+LOCAL_MULTILIB := both
+
+include $(BUILD_SHARED_LIBRARY)
+
+# Shared library for host
+# ========================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= libnativebridge3-dummy
+
+LOCAL_SRC_FILES:= $(NATIVE_BRIDGE3_COMMON_SRC_FILES)
+LOCAL_CLANG := true
+LOCAL_CFLAGS += -Werror -Wall
+LOCAL_CPPFLAGS := -std=gnu++11 -fvisibility=protected
+LOCAL_LDFLAGS := -ldl
+LOCAL_MULTILIB := both
+
+include $(BUILD_HOST_SHARED_LIBRARY)
+
+
diff --git a/libnativebridge/tests/DummyNativeBridge3.cpp b/libnativebridge/tests/DummyNativeBridge3.cpp
new file mode 100644
index 0000000..c538fa0
--- /dev/null
+++ b/libnativebridge/tests/DummyNativeBridge3.cpp
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// A dummy implementation of the native-bridge interface.
+
+#include "nativebridge/native_bridge.h"
+
+#include <signal.h>
+
+// NativeBridgeCallbacks implementations
+extern "C" bool native_bridge3_initialize(
+ const android::NativeBridgeRuntimeCallbacks* /* art_cbs */,
+ const char* /* app_code_cache_dir */,
+ const char* /* isa */) {
+ return true;
+}
+
+extern "C" void* native_bridge3_loadLibrary(const char* /* libpath */, int /* flag */) {
+ return nullptr;
+}
+
+extern "C" void* native_bridge3_getTrampoline(void* /* handle */, const char* /* name */,
+ const char* /* shorty */, uint32_t /* len */) {
+ return nullptr;
+}
+
+extern "C" bool native_bridge3_isSupported(const char* /* libpath */) {
+ return false;
+}
+
+extern "C" const struct android::NativeBridgeRuntimeValues* native_bridge3_getAppEnv(
+ const char* /* abi */) {
+ return nullptr;
+}
+
+extern "C" bool native_bridge3_isCompatibleWith(uint32_t version) {
+ // For testing, allow 1-3, but disallow 4+.
+ return version <= 3;
+}
+
+static bool native_bridge3_dummy_signal_handler(int, siginfo_t*, void*) {
+ // TODO: Implement something here. We'd either have to have a death test with a log here, or
+ // we'd have to be able to resume after the faulting instruction...
+ return true;
+}
+
+extern "C" android::NativeBridgeSignalHandlerFn native_bridge3_getSignalHandler(int signal) {
+ if (signal == SIGSEGV) {
+ return &native_bridge3_dummy_signal_handler;
+ }
+ return nullptr;
+}
+
+extern "C" int native_bridge3_unloadLibrary(void* /* handle */) {
+ return 0;
+}
+
+extern "C" char* native_bridge3_getError() {
+ return nullptr;
+}
+
+extern "C" bool native_bridge3_isPathSupported(const char* /* path */) {
+ return true;
+}
+
+extern "C" bool native_bridge3_initNamespace(const char* /* public_ns_sonames */,
+ const char* /* anon_ns_library_path */) {
+ return true;
+}
+
+extern "C" android::native_bridge_namespace_t*
+native_bridge3_createNamespace(const char* /* name */,
+ const char* /* ld_library_path */,
+ const char* /* default_library_path */,
+ uint64_t /* type */,
+ const char* /* permitted_when_isolated_path */,
+ android::native_bridge_namespace_t* /* parent_ns */) {
+ return nullptr;
+}
+
+extern "C" void* native_bridge3_loadLibraryExt(const char* /* libpath */,
+ int /* flag */,
+ android::native_bridge_namespace_t* /* ns */) {
+ return nullptr;
+}
+
+
+android::NativeBridgeCallbacks NativeBridgeItf {
+ // v1
+ .version = 3,
+ .initialize = &native_bridge3_initialize,
+ .loadLibrary = &native_bridge3_loadLibrary,
+ .getTrampoline = &native_bridge3_getTrampoline,
+ .isSupported = &native_bridge3_isSupported,
+ .getAppEnv = &native_bridge3_getAppEnv,
+ // v2
+ .isCompatibleWith = &native_bridge3_isCompatibleWith,
+ .getSignalHandler = &native_bridge3_getSignalHandler,
+ // v3
+ .unloadLibrary = &native_bridge3_unloadLibrary,
+ .getError = &native_bridge3_getError,
+ .isPathSupported = &native_bridge3_isPathSupported,
+ .initNamespace = &native_bridge3_initNamespace,
+ .createNamespace = &native_bridge3_createNamespace,
+ .loadLibraryExt = &native_bridge3_loadLibraryExt
+};
+
diff --git a/libnativebridge/tests/NativeBridge3CreateNamespace_test.cpp b/libnativebridge/tests/NativeBridge3CreateNamespace_test.cpp
new file mode 100644
index 0000000..668d942
--- /dev/null
+++ b/libnativebridge/tests/NativeBridge3CreateNamespace_test.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "NativeBridgeTest.h"
+
+namespace android {
+
+constexpr const char* kNativeBridgeLibrary3 = "libnativebridge3-dummy.so";
+
+TEST_F(NativeBridgeTest, V3_CreateNamespace) {
+ // Init
+ ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary3, nullptr));
+ ASSERT_TRUE(NativeBridgeAvailable());
+ ASSERT_TRUE(PreInitializeNativeBridge(".", "isa"));
+ ASSERT_TRUE(NativeBridgeAvailable());
+ ASSERT_TRUE(InitializeNativeBridge(nullptr, nullptr));
+ ASSERT_TRUE(NativeBridgeAvailable());
+
+ ASSERT_EQ(3U, NativeBridgeGetVersion());
+ ASSERT_EQ(nullptr, NativeBridgeCreateNamespace(nullptr, nullptr, nullptr,
+ 0, nullptr, nullptr));
+
+ // Clean-up code_cache
+ ASSERT_EQ(0, rmdir(kCodeCache));
+}
+
+} // namespace android
diff --git a/libnativebridge/tests/NativeBridge3GetError_test.cpp b/libnativebridge/tests/NativeBridge3GetError_test.cpp
new file mode 100644
index 0000000..0b9f582
--- /dev/null
+++ b/libnativebridge/tests/NativeBridge3GetError_test.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "NativeBridgeTest.h"
+
+namespace android {
+
+constexpr const char* kNativeBridgeLibrary3 = "libnativebridge3-dummy.so";
+
+TEST_F(NativeBridgeTest, V3_GetError) {
+ // Init
+ ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary3, nullptr));
+ ASSERT_TRUE(NativeBridgeAvailable());
+ ASSERT_TRUE(PreInitializeNativeBridge(".", "isa"));
+ ASSERT_TRUE(NativeBridgeAvailable());
+ ASSERT_TRUE(InitializeNativeBridge(nullptr, nullptr));
+ ASSERT_TRUE(NativeBridgeAvailable());
+
+ ASSERT_EQ(3U, NativeBridgeGetVersion());
+ ASSERT_EQ(nullptr, NativeBridgeGetError());
+
+ // Clean-up code_cache
+ ASSERT_EQ(0, rmdir(kCodeCache));
+}
+
+} // namespace android
diff --git a/libnativebridge/tests/NativeBridge3InitNamespace_test.cpp b/libnativebridge/tests/NativeBridge3InitNamespace_test.cpp
new file mode 100644
index 0000000..ae0fd2b
--- /dev/null
+++ b/libnativebridge/tests/NativeBridge3InitNamespace_test.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "NativeBridgeTest.h"
+
+namespace android {
+
+constexpr const char* kNativeBridgeLibrary3 = "libnativebridge3-dummy.so";
+
+TEST_F(NativeBridgeTest, V3_InitNamespace) {
+ // Init
+ ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary3, nullptr));
+ ASSERT_TRUE(NativeBridgeAvailable());
+ ASSERT_TRUE(PreInitializeNativeBridge(".", "isa"));
+ ASSERT_TRUE(NativeBridgeAvailable());
+ ASSERT_TRUE(InitializeNativeBridge(nullptr, nullptr));
+ ASSERT_TRUE(NativeBridgeAvailable());
+
+ ASSERT_EQ(3U, NativeBridgeGetVersion());
+ ASSERT_EQ(true, NativeBridgeInitNamespace(nullptr, nullptr));
+
+ // Clean-up code_cache
+ ASSERT_EQ(0, rmdir(kCodeCache));
+}
+
+} // namespace android
diff --git a/libnativebridge/tests/NativeBridge3IsPathSupported_test.cpp b/libnativebridge/tests/NativeBridge3IsPathSupported_test.cpp
new file mode 100644
index 0000000..325e40b
--- /dev/null
+++ b/libnativebridge/tests/NativeBridge3IsPathSupported_test.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "NativeBridgeTest.h"
+
+namespace android {
+
+constexpr const char* kNativeBridgeLibrary3 = "libnativebridge3-dummy.so";
+
+TEST_F(NativeBridgeTest, V3_IsPathSupported) {
+ // Init
+ ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary3, nullptr));
+ ASSERT_TRUE(NativeBridgeAvailable());
+ ASSERT_TRUE(PreInitializeNativeBridge(".", "isa"));
+ ASSERT_TRUE(NativeBridgeAvailable());
+ ASSERT_TRUE(InitializeNativeBridge(nullptr, nullptr));
+ ASSERT_TRUE(NativeBridgeAvailable());
+
+ ASSERT_EQ(3U, NativeBridgeGetVersion());
+ ASSERT_EQ(true, NativeBridgeIsPathSupported(nullptr));
+
+ // Clean-up code_cache
+ ASSERT_EQ(0, rmdir(kCodeCache));
+}
+
+} // namespace android
diff --git a/libnativebridge/tests/NativeBridge3LoadLibraryExt_test.cpp b/libnativebridge/tests/NativeBridge3LoadLibraryExt_test.cpp
new file mode 100644
index 0000000..4caeb44
--- /dev/null
+++ b/libnativebridge/tests/NativeBridge3LoadLibraryExt_test.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "NativeBridgeTest.h"
+
+namespace android {
+
+constexpr const char* kNativeBridgeLibrary3 = "libnativebridge3-dummy.so";
+
+TEST_F(NativeBridgeTest, V3_LoadLibraryExt) {
+ // Init
+ ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary3, nullptr));
+ ASSERT_TRUE(NativeBridgeAvailable());
+ ASSERT_TRUE(PreInitializeNativeBridge(".", "isa"));
+ ASSERT_TRUE(NativeBridgeAvailable());
+ ASSERT_TRUE(InitializeNativeBridge(nullptr, nullptr));
+ ASSERT_TRUE(NativeBridgeAvailable());
+
+ ASSERT_EQ(3U, NativeBridgeGetVersion());
+ ASSERT_EQ(nullptr, NativeBridgeLoadLibraryExt(nullptr, 0, nullptr));
+
+ // Clean-up code_cache
+ ASSERT_EQ(0, rmdir(kCodeCache));
+}
+
+} // namespace android
diff --git a/libnativebridge/tests/NativeBridge3UnloadLibrary_test.cpp b/libnativebridge/tests/NativeBridge3UnloadLibrary_test.cpp
new file mode 100644
index 0000000..93a979c
--- /dev/null
+++ b/libnativebridge/tests/NativeBridge3UnloadLibrary_test.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "NativeBridgeTest.h"
+
+namespace android {
+
+constexpr const char* kNativeBridgeLibrary3 = "libnativebridge3-dummy.so";
+
+TEST_F(NativeBridgeTest, V3_UnloadLibrary) {
+ // Init
+ ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary3, nullptr));
+ ASSERT_TRUE(NativeBridgeAvailable());
+ ASSERT_TRUE(PreInitializeNativeBridge(".", "isa"));
+ ASSERT_TRUE(NativeBridgeAvailable());
+ ASSERT_TRUE(InitializeNativeBridge(nullptr, nullptr));
+ ASSERT_TRUE(NativeBridgeAvailable());
+
+ ASSERT_EQ(3U, NativeBridgeGetVersion());
+ ASSERT_EQ(0, NativeBridgeUnloadLibrary(nullptr));
+
+ // Clean-up code_cache
+ ASSERT_EQ(0, rmdir(kCodeCache));
+}
+
+} // namespace android
diff --git a/libnativebridge/tests/NativeBridgeTest.h b/libnativebridge/tests/NativeBridgeTest.h
index d489420..0f99816 100644
--- a/libnativebridge/tests/NativeBridgeTest.h
+++ b/libnativebridge/tests/NativeBridgeTest.h
@@ -25,6 +25,8 @@
constexpr const char* kNativeBridgeLibrary = "libnativebridge-dummy.so";
constexpr const char* kCodeCache = "./code_cache";
constexpr const char* kCodeCacheStatFail = "./code_cache/temp";
+constexpr const char* kNativeBridgeLibrary2 = "libnativebridge2-dummy.so";
+constexpr const char* kNativeBridgeLibrary3 = "libnativebridge3-dummy.so";
namespace android {
diff --git a/libnativeloader/Android.bp b/libnativeloader/Android.bp
index 30531bc..9d33899 100644
--- a/libnativeloader/Android.bp
+++ b/libnativeloader/Android.bp
@@ -8,6 +8,7 @@
"libnativehelper",
"liblog",
"libcutils",
+ "libnativebridge",
],
static_libs: ["libbase"],
target: {
diff --git a/libnativeloader/include/nativeloader/native_loader.h b/libnativeloader/include/nativeloader/native_loader.h
index 2a6aaec..99ae3a7 100644
--- a/libnativeloader/include/nativeloader/native_loader.h
+++ b/libnativeloader/include/nativeloader/native_loader.h
@@ -19,6 +19,7 @@
#include "jni.h"
#include <stdint.h>
+#include <string>
#if defined(__ANDROID__)
#include <android/dlext.h>
#endif
@@ -41,10 +42,12 @@
int32_t target_sdk_version,
const char* path,
jobject class_loader,
- jstring library_path);
+ jstring library_path,
+ bool* needs_native_bridge,
+ std::string* error_msg);
__attribute__((visibility("default")))
-bool CloseNativeLibrary(void* handle);
+bool CloseNativeLibrary(void* handle, const bool needs_native_bridge);
#if defined(__ANDROID__)
// Look up linker namespace by class_loader. Returns nullptr if
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index 3a6e54d..fb95cb6 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -24,6 +24,7 @@
#include "android/log.h"
#include "cutils/properties.h"
#endif
+#include "nativebridge/native_bridge.h"
#include <algorithm>
#include <vector>
@@ -34,11 +35,53 @@
#include <android-base/macros.h>
#include <android-base/strings.h>
+#define CHECK(predicate) LOG_ALWAYS_FATAL_IF(!(predicate),\
+ "%s:%d: %s CHECK '" #predicate "' failed.",\
+ __FILE__, __LINE__, __FUNCTION__)
+
namespace android {
#if defined(__ANDROID__)
-static constexpr const char* kPublicNativeLibrariesSystemConfigPathFromRoot = "/etc/public.libraries.txt";
-static constexpr const char* kPublicNativeLibrariesVendorConfig = "/vendor/etc/public.libraries.txt";
+class NativeLoaderNamespace {
+ public:
+ NativeLoaderNamespace()
+ : android_ns_(nullptr), native_bridge_ns_(nullptr) { }
+
+ explicit NativeLoaderNamespace(android_namespace_t* ns)
+ : android_ns_(ns), native_bridge_ns_(nullptr) { }
+
+ explicit NativeLoaderNamespace(native_bridge_namespace_t* ns)
+ : android_ns_(nullptr), native_bridge_ns_(ns) { }
+
+ NativeLoaderNamespace(NativeLoaderNamespace&& that) = default;
+ NativeLoaderNamespace(const NativeLoaderNamespace& that) = default;
+
+ NativeLoaderNamespace& operator=(const NativeLoaderNamespace& that) = default;
+
+ android_namespace_t* get_android_ns() const {
+ CHECK(native_bridge_ns_ == nullptr);
+ return android_ns_;
+ }
+
+ native_bridge_namespace_t* get_native_bridge_ns() const {
+ CHECK(android_ns_ == nullptr);
+ return native_bridge_ns_;
+ }
+
+ bool is_android_namespace() const {
+ return native_bridge_ns_ == nullptr;
+ }
+
+ private:
+ // Only one of them can be not null
+ android_namespace_t* android_ns_;
+ native_bridge_namespace_t* native_bridge_ns_;
+};
+
+static constexpr const char* kPublicNativeLibrariesSystemConfigPathFromRoot =
+ "/etc/public.libraries.txt";
+static constexpr const char* kPublicNativeLibrariesVendorConfig =
+ "/vendor/etc/public.libraries.txt";
// (http://b/27588281) This is a workaround for apps using custom classloaders and calling
// System.load() with an absolute path which is outside of the classloader library search path.
@@ -55,11 +98,13 @@
public:
LibraryNamespaces() : initialized_(false) { }
- android_namespace_t* Create(JNIEnv* env,
- jobject class_loader,
- bool is_shared,
- jstring java_library_path,
- jstring java_permitted_path) {
+ bool Create(JNIEnv* env,
+ jobject class_loader,
+ bool is_shared,
+ jstring java_library_path,
+ jstring java_permitted_path,
+ NativeLoaderNamespace* ns,
+ std::string* error_msg) {
std::string library_path; // empty string by default.
if (java_library_path != nullptr) {
@@ -82,13 +127,13 @@
}
}
- if (!initialized_ && !InitPublicNamespace(library_path.c_str())) {
- return nullptr;
+ if (!initialized_ && !InitPublicNamespace(library_path.c_str(), error_msg)) {
+ return false;
}
- android_namespace_t* ns = FindNamespaceByClassLoader(env, class_loader);
+ bool found = FindNamespaceByClassLoader(env, class_loader, nullptr);
- LOG_ALWAYS_FATAL_IF(ns != nullptr,
+ LOG_ALWAYS_FATAL_IF(found,
"There is already a namespace associated with this classloader");
uint64_t namespace_type = ANDROID_NAMESPACE_TYPE_ISOLATED;
@@ -96,28 +141,66 @@
namespace_type |= ANDROID_NAMESPACE_TYPE_SHARED;
}
- android_namespace_t* parent_ns = FindParentNamespaceByClassLoader(env, class_loader);
+ NativeLoaderNamespace parent_ns;
+ bool found_parent_namespace = FindParentNamespaceByClassLoader(env, class_loader, &parent_ns);
- ns = android_create_namespace("classloader-namespace",
- nullptr,
- library_path.c_str(),
- namespace_type,
- permitted_path.c_str(),
- parent_ns);
+ bool is_native_bridge = false;
- if (ns != nullptr) {
- namespaces_.push_back(std::make_pair(env->NewWeakGlobalRef(class_loader), ns));
+ if (found_parent_namespace) {
+ is_native_bridge = !parent_ns.is_android_namespace();
+ } else if (!library_path.empty()) {
+ is_native_bridge = NativeBridgeIsPathSupported(library_path.c_str());
}
- return ns;
+ NativeLoaderNamespace native_loader_ns;
+ if (!is_native_bridge) {
+ android_namespace_t* ns = android_create_namespace("classloader-namespace",
+ nullptr,
+ library_path.c_str(),
+ namespace_type,
+ permitted_path.c_str(),
+ parent_ns.get_android_ns());
+ if (ns == nullptr) {
+ *error_msg = dlerror();
+ return false;
+ }
+
+ native_loader_ns = NativeLoaderNamespace(ns);
+ } else {
+ native_bridge_namespace_t* ns = NativeBridgeCreateNamespace("classloader-namespace",
+ nullptr,
+ library_path.c_str(),
+ namespace_type,
+ permitted_path.c_str(),
+ parent_ns.get_native_bridge_ns());
+ if (ns == nullptr) {
+ *error_msg = NativeBridgeGetError();
+ return false;
+ }
+
+ native_loader_ns = NativeLoaderNamespace(ns);
+ }
+
+ namespaces_.push_back(std::make_pair(env->NewWeakGlobalRef(class_loader), native_loader_ns));
+
+ *ns = native_loader_ns;
+ return true;
}
- android_namespace_t* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
+ bool FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader, NativeLoaderNamespace* ns) {
auto it = std::find_if(namespaces_.begin(), namespaces_.end(),
- [&](const std::pair<jweak, android_namespace_t*>& value) {
+ [&](const std::pair<jweak, NativeLoaderNamespace>& value) {
return env->IsSameObject(value.first, class_loader);
});
- return it != namespaces_.end() ? it->second : nullptr;
+ if (it != namespaces_.end()) {
+ if (ns != nullptr) {
+ *ns = it->second;
+ }
+
+ return true;
+ }
+
+ return false;
}
void Initialize() {
@@ -217,12 +300,25 @@
return true;
}
- bool InitPublicNamespace(const char* library_path) {
+ bool InitPublicNamespace(const char* library_path, std::string* error_msg) {
+ // Ask native bride if this apps library path should be handled by it
+ bool is_native_bridge = NativeBridgeIsPathSupported(library_path);
+
// (http://b/25844435) - Some apps call dlopen from generated code (mono jited
// code is one example) unknown to linker in which case linker uses anonymous
// namespace. The second argument specifies the search path for the anonymous
// namespace which is the library_path of the classloader.
- initialized_ = android_init_namespaces(public_libraries_.c_str(), library_path);
+ if (!is_native_bridge) {
+ initialized_ = android_init_namespaces(public_libraries_.c_str(), library_path);
+ if (!initialized_) {
+ *error_msg = dlerror();
+ }
+ } else {
+ initialized_ = NativeBridgeInitNamespace(public_libraries_.c_str(), library_path);
+ if (!initialized_) {
+ *error_msg = NativeBridgeGetError();
+ }
+ }
return initialized_;
}
@@ -236,22 +332,24 @@
return env->CallObjectMethod(class_loader, get_parent);
}
- android_namespace_t* FindParentNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
+ bool FindParentNamespaceByClassLoader(JNIEnv* env,
+ jobject class_loader,
+ NativeLoaderNamespace* ns) {
jobject parent_class_loader = GetParentClassLoader(env, class_loader);
while (parent_class_loader != nullptr) {
- android_namespace_t* ns = FindNamespaceByClassLoader(env, parent_class_loader);
- if (ns != nullptr) {
- return ns;
+ if (FindNamespaceByClassLoader(env, parent_class_loader, ns)) {
+ return true;
}
parent_class_loader = GetParentClassLoader(env, parent_class_loader);
}
- return nullptr;
+
+ return false;
}
bool initialized_;
- std::vector<std::pair<jweak, android_namespace_t*>> namespaces_;
+ std::vector<std::pair<jweak, NativeLoaderNamespace>> namespaces_;
std::string public_libraries_;
@@ -285,13 +383,18 @@
#if defined(__ANDROID__)
UNUSED(target_sdk_version);
std::lock_guard<std::mutex> guard(g_namespaces_mutex);
- android_namespace_t* ns = g_namespaces->Create(env,
- class_loader,
- is_shared,
- library_path,
- permitted_path);
- if (ns == nullptr) {
- return env->NewStringUTF(dlerror());
+
+ std::string error_msg;
+ NativeLoaderNamespace ns;
+ bool success = g_namespaces->Create(env,
+ class_loader,
+ is_shared,
+ library_path,
+ permitted_path,
+ &ns,
+ &error_msg);
+ if (!success) {
+ return env->NewStringUTF(error_msg.c_str());
}
#else
UNUSED(env, target_sdk_version, class_loader, is_shared,
@@ -304,44 +407,83 @@
int32_t target_sdk_version,
const char* path,
jobject class_loader,
- jstring library_path) {
+ jstring library_path,
+ bool* needs_native_bridge,
+ std::string* error_msg) {
#if defined(__ANDROID__)
UNUSED(target_sdk_version);
if (class_loader == nullptr) {
+ *needs_native_bridge = false;
return dlopen(path, RTLD_NOW);
}
std::lock_guard<std::mutex> guard(g_namespaces_mutex);
- android_namespace_t* ns = g_namespaces->FindNamespaceByClassLoader(env, class_loader);
+ NativeLoaderNamespace ns;
- if (ns == nullptr) {
+ if (!g_namespaces->FindNamespaceByClassLoader(env, class_loader, &ns)) {
// This is the case where the classloader was not created by ApplicationLoaders
// In this case we create an isolated not-shared namespace for it.
- ns = g_namespaces->Create(env, class_loader, false, library_path, nullptr);
- if (ns == nullptr) {
+ if (!g_namespaces->Create(env, class_loader, false, library_path, nullptr, &ns, error_msg)) {
return nullptr;
}
}
- android_dlextinfo extinfo;
- extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
- extinfo.library_namespace = ns;
+ if (ns.is_android_namespace()) {
+ android_dlextinfo extinfo;
+ extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
+ extinfo.library_namespace = ns.get_android_ns();
- return android_dlopen_ext(path, RTLD_NOW, &extinfo);
+ void* handle = android_dlopen_ext(path, RTLD_NOW, &extinfo);
+ if (handle == nullptr) {
+ *error_msg = dlerror();
+ }
+ *needs_native_bridge = false;
+ return handle;
+ } else {
+ void* handle = NativeBridgeLoadLibraryExt(path, RTLD_NOW, ns.get_native_bridge_ns());
+ if (handle == nullptr) {
+ *error_msg = NativeBridgeGetError();
+ }
+ *needs_native_bridge = true;
+ return handle;
+ }
#else
UNUSED(env, target_sdk_version, class_loader, library_path);
- return dlopen(path, RTLD_NOW);
+ *needs_native_bridge = false;
+ void* handle = dlopen(path, RTLD_NOW);
+ if (handle == nullptr) {
+ if (NativeBridgeIsSupported(path)) {
+ *needs_native_bridge = true;
+ handle = NativeBridgeLoadLibrary(path, RTLD_NOW);
+ if (handle == nullptr) {
+ *error_msg = NativeBridgeGetError();
+ }
+ } else {
+ *needs_native_bridge = false;
+ *error_msg = dlerror();
+ }
+ }
+ return handle;
#endif
}
-bool CloseNativeLibrary(void* handle) {
- return dlclose(handle) == 0;
+bool CloseNativeLibrary(void* handle, const bool needs_native_bridge) {
+ return needs_native_bridge ? NativeBridgeUnloadLibrary(handle) :
+ dlclose(handle);
}
#if defined(__ANDROID__)
android_namespace_t* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
std::lock_guard<std::mutex> guard(g_namespaces_mutex);
- return g_namespaces->FindNamespaceByClassLoader(env, class_loader);
+ // native_bridge_namespaces are not supported for callers of this function.
+ // At the moment this is libwebviewchromium_loader and vulkan.
+ NativeLoaderNamespace ns;
+ if (g_namespaces->FindNamespaceByClassLoader(env, class_loader, &ns)) {
+ CHECK(ns.is_android_namespace());
+ return ns.get_android_ns();
+ }
+
+ return nullptr;
}
#endif
diff --git a/libusbhost/include/usbhost/usbhost.h b/libusbhost/include/usbhost/usbhost.h
index 84594c8..c17f3c7 100644
--- a/libusbhost/include/usbhost/usbhost.h
+++ b/libusbhost/include/usbhost/usbhost.h
@@ -144,17 +144,17 @@
* usb_device_get_product_name and usb_device_get_serial.
* Call free() to free the result when you are done with it.
*/
-char* usb_device_get_string(struct usb_device *device, int id);
+char* usb_device_get_string(struct usb_device *device, int id, int timeout);
/* Returns the manufacturer name for the USB device.
* Call free() to free the result when you are done with it.
*/
-char* usb_device_get_manufacturer_name(struct usb_device *device);
+char* usb_device_get_manufacturer_name(struct usb_device *device, int timeout);
/* Returns the product name for the USB device.
* Call free() to free the result when you are done with it.
*/
-char* usb_device_get_product_name(struct usb_device *device);
+char* usb_device_get_product_name(struct usb_device *device, int timeout);
/* Returns the version number for the USB device.
*/
@@ -163,7 +163,7 @@
/* Returns the USB serial number for the USB device.
* Call free() to free the result when you are done with it.
*/
-char* usb_device_get_serial(struct usb_device *device);
+char* usb_device_get_serial(struct usb_device *device, int timeout);
/* Returns true if we have write access to the USB device,
* and false if we only have access to the USB device configuration.
diff --git a/libusbhost/usbhost.c b/libusbhost/usbhost.c
index 68aca17..9bec6e3 100644
--- a/libusbhost/usbhost.c
+++ b/libusbhost/usbhost.c
@@ -449,7 +449,7 @@
return (struct usb_device_descriptor*)device->desc;
}
-char* usb_device_get_string(struct usb_device *device, int id)
+char* usb_device_get_string(struct usb_device *device, int id, int timeout)
{
char string[256];
__u16 buffer[MAX_STRING_DESCRIPTOR_LENGTH / sizeof(__u16)];
@@ -465,7 +465,8 @@
// read list of supported languages
result = usb_device_control_transfer(device,
USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE, USB_REQ_GET_DESCRIPTOR,
- (USB_DT_STRING << 8) | 0, 0, languages, sizeof(languages), 0);
+ (USB_DT_STRING << 8) | 0, 0, languages, sizeof(languages),
+ timeout);
if (result > 0)
languageCount = (result - 2) / 2;
@@ -474,7 +475,8 @@
result = usb_device_control_transfer(device,
USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE, USB_REQ_GET_DESCRIPTOR,
- (USB_DT_STRING << 8) | id, languages[i], buffer, sizeof(buffer), 0);
+ (USB_DT_STRING << 8) | id, languages[i], buffer, sizeof(buffer),
+ timeout);
if (result > 0) {
int i;
// skip first word, and copy the rest to the string, changing shorts to bytes.
@@ -489,16 +491,16 @@
return NULL;
}
-char* usb_device_get_manufacturer_name(struct usb_device *device)
+char* usb_device_get_manufacturer_name(struct usb_device *device, int timeout)
{
struct usb_device_descriptor *desc = (struct usb_device_descriptor *)device->desc;
- return usb_device_get_string(device, desc->iManufacturer);
+ return usb_device_get_string(device, desc->iManufacturer, timeout);
}
-char* usb_device_get_product_name(struct usb_device *device)
+char* usb_device_get_product_name(struct usb_device *device, int timeout)
{
struct usb_device_descriptor *desc = (struct usb_device_descriptor *)device->desc;
- return usb_device_get_string(device, desc->iProduct);
+ return usb_device_get_string(device, desc->iProduct, timeout);
}
int usb_device_get_version(struct usb_device *device)
@@ -507,10 +509,10 @@
return desc->bcdUSB;
}
-char* usb_device_get_serial(struct usb_device *device)
+char* usb_device_get_serial(struct usb_device *device, int timeout)
{
struct usb_device_descriptor *desc = (struct usb_device_descriptor *)device->desc;
- return usb_device_get_string(device, desc->iSerialNumber);
+ return usb_device_get_string(device, desc->iSerialNumber, timeout);
}
int usb_device_is_writeable(struct usb_device *device)
@@ -711,4 +713,3 @@
struct usbdevfs_urb *urb = ((struct usbdevfs_urb*)req->private_data);
return ioctl(req->dev->fd, USBDEVFS_DISCARDURB, urb);
}
-
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index 5cab7a8..a009433 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -13,6 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+// for manual checking of stale entries during LogBuffer::erase()
+//#define DEBUG_CHECK_FOR_STALE_ENTRIES
#include <ctype.h>
#include <errno.h>
@@ -256,6 +258,11 @@
log_id_for_each(i) {
doSetLast |= setLast[i] = mLastSet[i] && (it == mLast[i]);
}
+#ifdef DEBUG_CHECK_FOR_STALE_ENTRIES
+ LogBufferElementCollection::iterator bad = it;
+ int key = ((id == LOG_ID_EVENTS) || (id == LOG_ID_SECURITY)) ?
+ element->getTag() : element->getUid();
+#endif
it = mLogElements.erase(it);
if (doSetLast) {
log_id_for_each(i) {
@@ -269,6 +276,27 @@
}
}
}
+#ifdef DEBUG_CHECK_FOR_STALE_ENTRIES
+ log_id_for_each(i) {
+ for(auto b : mLastWorst[i]) {
+ if (bad == b.second) {
+ android::prdebug("stale mLastWorst[%d] key=%d mykey=%d\n",
+ i, b.first, key);
+ }
+ }
+ for(auto b : mLastWorstPidOfSystem[i]) {
+ if (bad == b.second) {
+ android::prdebug("stale mLastWorstPidOfSystem[%d] pid=%d\n",
+ i, b.first);
+ }
+ }
+ if (mLastSet[i] && (bad == mLast[i])) {
+ android::prdebug("stale mLast[%d]\n", i);
+ mLastSet[i] = false;
+ mLast[i] = mLogElements.begin();
+ }
+ }
+#endif
if (coalesce) {
stats.erase(element);
} else {
diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp
index a939002..f5c60c7 100644
--- a/logd/LogBufferElement.cpp
+++ b/logd/LogBufferElement.cpp
@@ -36,29 +36,24 @@
LogBufferElement::LogBufferElement(log_id_t log_id, log_time realtime,
uid_t uid, pid_t pid, pid_t tid,
const char *msg, unsigned short len) :
- mLogId(log_id),
mUid(uid),
mPid(pid),
mTid(tid),
- mMsgLen(len),
mSequence(sequence.fetch_add(1, memory_order_relaxed)),
- mRealTime(realtime) {
+ mRealTime(realtime),
+ mMsgLen(len),
+ mLogId(log_id) {
mMsg = new char[len];
memcpy(mMsg, msg, len);
+ mTag = (isBinary() && (mMsgLen >= sizeof(uint32_t))) ?
+ le32toh(reinterpret_cast<android_event_header_t *>(mMsg)->tag) :
+ 0;
}
LogBufferElement::~LogBufferElement() {
delete [] mMsg;
}
-uint32_t LogBufferElement::getTag() const {
- if (((mLogId != LOG_ID_EVENTS) && (mLogId != LOG_ID_SECURITY)) ||
- !mMsg || (mMsgLen < sizeof(uint32_t))) {
- return 0;
- }
- return le32toh(reinterpret_cast<android_event_header_t *>(mMsg)->tag);
-}
-
// caller must own and free character string
char *android::tidToName(pid_t tid) {
char *retval = NULL;
@@ -164,7 +159,7 @@
size_t hdrLen;
// LOG_ID_SECURITY not strictly needed since spam filter not activated,
// but required for accuracy.
- if ((mLogId == LOG_ID_EVENTS) || (mLogId == LOG_ID_SECURITY)) {
+ if (isBinary()) {
hdrLen = sizeof(android_log_event_string_t);
} else {
hdrLen = 1 + sizeof(tag);
@@ -178,7 +173,7 @@
}
size_t retval = hdrLen + len;
- if ((mLogId == LOG_ID_EVENTS) || (mLogId == LOG_ID_SECURITY)) {
+ if (isBinary()) {
android_log_event_string_t *event =
reinterpret_cast<android_log_event_string_t *>(buffer);
diff --git a/logd/LogBufferElement.h b/logd/LogBufferElement.h
index 2c7fd44..fb7fbed 100644
--- a/logd/LogBufferElement.h
+++ b/logd/LogBufferElement.h
@@ -36,33 +36,40 @@
friend LogBuffer;
- const log_id_t mLogId;
- const uid_t mUid;
- const pid_t mPid;
- const pid_t mTid;
- char *mMsg;
- union {
- const unsigned short mMsgLen; // mMSg != NULL
- unsigned short mDropped; // mMsg == NULL
- };
+ // sized to match reality of incoming log packets
+ uint32_t mTag; // only valid for isBinary()
+ const uint32_t mUid;
+ const uint32_t mPid;
+ const uint32_t mTid;
const uint64_t mSequence;
log_time mRealTime;
+ char *mMsg;
+ union {
+ const uint16_t mMsgLen; // mMSg != NULL
+ uint16_t mDropped; // mMsg == NULL
+ };
+ const uint8_t mLogId;
+
static atomic_int_fast64_t sequence;
// assumption: mMsg == NULL
size_t populateDroppedMessage(char *&buffer,
LogBuffer *parent);
-
public:
LogBufferElement(log_id_t log_id, log_time realtime,
uid_t uid, pid_t pid, pid_t tid,
const char *msg, unsigned short len);
virtual ~LogBufferElement();
- log_id_t getLogId() const { return mLogId; }
+ bool isBinary(void) const {
+ return (mLogId == LOG_ID_EVENTS) || (mLogId == LOG_ID_SECURITY);
+ }
+
+ log_id_t getLogId() const { return static_cast<log_id_t>(mLogId); }
uid_t getUid(void) const { return mUid; }
pid_t getPid(void) const { return mPid; }
pid_t getTid(void) const { return mTid; }
+ uint32_t getTag() const { return mTag; }
unsigned short getDropped(void) const { return mMsg ? 0 : mDropped; }
unsigned short setDropped(unsigned short value) {
if (mMsg) {
@@ -76,8 +83,6 @@
static uint64_t getCurrentSequence(void) { return sequence.load(memory_order_relaxed); }
log_time getRealTime(void) const { return mRealTime; }
- uint32_t getTag(void) const;
-
static const uint64_t FLUSH_ERROR;
uint64_t flushTo(SocketClient *writer, LogBuffer *parent, bool privileged);
};