using ::android::base::Result; using ::android::nativeloader::LibraryNamespaces;
// NATIVELOADER_DEFAULT_NAMESPACE_LIBS is an environment variable that can be // used to list extra libraries (separated by ":") that libnativeloader will // load from the default namespace. The libraries must be listed without paths, // and then LD_LIBRARY_PATH is typically set to the directories to load them // from. The libraries will be available in all classloader namespaces, and also // in the fallback namespace used when no classloader is given. // // kNativeloaderExtraLibs is the name of that fallback namespace. // // NATIVELOADER_DEFAULT_NAMESPACE_LIBS is intended to be used for testing only, // and in particular in the ART run tests that are executed through dalvikvm in // the APEX. In that case the default namespace links to the ART namespace // (com_android_art) for all libraries, which means this can be used to load // test libraries that depend on ART internal libraries. // // There's also code in art/dalvikvm.cc to add links from com_android_art back // to the default namespace for NATIVELOADER_DEFAULT_NAMESPACE_LIBS, enabling // access in the opposite direction as well. Useful e.g. to load ART plugins in // NATIVELOADER_DEFAULT_NAMESPACE_LIBS.
constexpr constchar* kNativeloaderExtraLibs = "nativeloader-extra-libs";
std::optional<NativeLoaderNamespace> FindApexNamespace(constchar* caller_location) {
std::optional<std::string> name = nativeloader::FindApexNamespaceName(caller_location); if (name.has_value()) { // Native Bridge is never used for APEXes.
Result<NativeLoaderNamespace> ns =
NativeLoaderNamespace::GetExportedNamespace(name.value(), /*is_bridged=*/false);
LOG_ALWAYS_FATAL_IF(!ns.ok(), "Error finding ns %s for APEX location %s: %s",
name.value().c_str(),
caller_location,
ns.error().message().c_str()); return ns.value();
} return std::nullopt;
}
Result<NativeLoaderNamespace> GetNamespaceForApiDomain(nativeloader::ApiDomain api_domain, bool is_bridged) { switch (api_domain) { case nativeloader::API_DOMAIN_VENDOR: return NativeLoaderNamespace::GetExportedNamespace(nativeloader::kVendorNamespaceName,
is_bridged); case nativeloader::API_DOMAIN_PRODUCT: return NativeLoaderNamespace::GetExportedNamespace(nativeloader::kProductNamespaceName,
is_bridged); case nativeloader::API_DOMAIN_SYSTEM: return NativeLoaderNamespace::GetSystemNamespace(is_bridged); default:
LOG_FATAL("Invalid API domain %d", api_domain);
UNREACHABLE();
}
}
Result<void> CreateNativeloaderDefaultNamespaceLibsLink(NativeLoaderNamespace& ns)
REQUIRES(g_namespaces_mutex) { constchar* links = getenv("NATIVELOADER_DEFAULT_NAMESPACE_LIBS"); if (links == nullptr || *links == 0) { return {};
} // Pass nullptr to Link() to create a link to the default namespace without // requiring it to be visible. return ns.Link(nullptr, links);
}
// If the given path matches a library in NATIVELOADER_DEFAULT_NAMESPACE_LIBS // then load it in the nativeloader-extra-libs namespace, otherwise return // nullptr without error.
Result<void*> TryLoadNativeloaderExtraLib(constchar* path) { constchar* links = getenv("NATIVELOADER_DEFAULT_NAMESPACE_LIBS"); if (links == nullptr || *links == 0) { return nullptr;
}
std::vector<std::string> lib_list = base::Split(links, ":"); if (std::find(lib_list.begin(), lib_list.end(), path) == lib_list.end()) { return nullptr;
}
void* OpenNativeLibrary(JNIEnv* env,
int32_t target_sdk_version, constchar* path,
jobject class_loader, constchar* caller_location,
jstring library_path_j, bool* needs_native_bridge, char** error_msg) { #ifdefined(ART_TARGET_ANDROID) if (class_loader == nullptr) { // class_loader is null only for the boot class loader (see // IsBootClassLoader call in JavaVMExt::LoadNativeLibrary), i.e. the caller // is in the boot classpath.
*needs_native_bridge = false; if (caller_location != nullptr) {
std::optional<NativeLoaderNamespace> ns = FindApexNamespace(caller_location); if (ns.has_value()) { const android_dlextinfo dlextinfo = {
.flags = ANDROID_DLEXT_USE_NAMESPACE,
.library_namespace = ns.value().ToRawAndroidNamespace(),
}; void* handle = android_dlopen_ext(path, RTLD_NOW, &dlextinfo); char* dlerror_msg = handle == nullptr ? strdup(dlerror()) : nullptr;
ALOGD("Load %s using APEX ns %s for caller %s: %s",
path,
ns.value().name().c_str(),
caller_location,
dlerror_msg == nullptr ? "ok" : dlerror_msg); if (dlerror_msg != nullptr) {
*error_msg = dlerror_msg;
} return handle;
}
}
// Check if the library is in NATIVELOADER_DEFAULT_NAMESPACE_LIBS and should // be loaded from the kNativeloaderExtraLibs namespace.
{
Result<void*> handle = TryLoadNativeloaderExtraLib(path); if (!handle.ok()) {
*error_msg = strdup(handle.error().message().c_str()); return nullptr;
} if (handle.value() != nullptr) { return handle.value();
}
}
if (bypass_loading_for_b349878424 &&
(strcmp("libsobridge.so", path) == 0 || strcmp("libwalkstack.so", path) == 0)) { // Load a different library to pretend the loading was successful. This // allows the device to boot.
ALOGD("Loading libbase.so instead of %s due to b/349878424", path);
path = "libbase.so";
}
// Fall back to the system namespace. This happens for preloaded JNI // libraries in the zygote. void* handle = OpenSystemLibrary(path, RTLD_NOW); char* dlerror_msg = handle == nullptr ? strdup(dlerror()) : nullptr;
ALOGD("Load %s using system ns (caller=%s): %s",
path,
caller_location == nullptr ? "<unknown>" : caller_location,
dlerror_msg == nullptr ? "ok" : dlerror_msg); if (dlerror_msg != nullptr) {
*error_msg = dlerror_msg;
} return handle;
}
// If the caller is in any of the system image partitions and the library is // in the same partition then load it without regards to public library // restrictions. This is only done if the library is specified by an absolute // path, so we don't affect the lookup process for libraries specified by name // only. if (caller_location != nullptr && // Apps in the partition may have their own native libraries which should // be loaded with the app's classloader namespace, so only do this for // libraries in the partition-wide lib(64) directories.
nativeloader::IsPartitionNativeLibPath(path) && // Don't do this if the system image is older than V, to avoid any compat // issues with apps and shared libs in them.
android::modules::sdklevel::IsAtLeastV()) {
nativeloader::ApiDomain caller_api_domain = nativeloader::GetApiDomainFromPath(caller_location); if (caller_api_domain != nativeloader::API_DOMAIN_DEFAULT) {
nativeloader::ApiDomain library_api_domain = nativeloader::GetApiDomainFromPath(path);
if (library_api_domain == caller_api_domain) { bool is_bridged = false; if (library_path_j != nullptr) {
ScopedUtfChars library_path_utf_chars(env, library_path_j); if (library_path_utf_chars[0] != '\0') {
is_bridged = NativeBridgeIsPathSupported(library_path_utf_chars.c_str());
}
}
Result<NativeLoaderNamespace> ns = GetNamespaceForApiDomain(caller_api_domain, is_bridged); if (!ns.ok()) {
ALOGD("Failed to find ns for caller %s in API domain %d to load %s (is_bridged=%b): %s",
caller_location,
caller_api_domain,
path,
is_bridged,
ns.error().message().c_str());
*error_msg = strdup(ns.error().message().c_str()); return nullptr;
}
*needs_native_bridge = ns.value().IsBridged();
Result<void*> handle = ns.value().Load(path);
ALOGD("Load %s using ns %s for caller %s in same partition (is_bridged=%b): %s",
path,
ns.value().name().c_str(),
caller_location,
is_bridged,
handle.ok() ? "ok" : handle.error().message().c_str()); if (!handle.ok()) {
*error_msg = strdup(handle.error().message().c_str()); return nullptr;
} return handle.value();
}
}
}
if (ns == nullptr) { // This is the case where the classloader was not created by ApplicationLoaders // In this case we create an isolated not-shared namespace for it. const std::string empty_dex_path;
Result<NativeLoaderNamespace*> res =
CreateClassLoaderNamespaceLocked(env,
target_sdk_version,
class_loader,
nativeloader::API_DOMAIN_DEFAULT, /*is_shared=*/false,
empty_dex_path,
library_path_j, /*permitted_path_j=*/nullptr, /*uses_library_list_j=*/nullptr); if (!res.ok()) {
ALOGD("Failed to create isolated ns for %s (caller=%s)",
path,
caller_location == nullptr ? "<unknown>" : caller_location);
*error_msg = strdup(res.error().message().c_str()); return nullptr;
}
ns = res.value();
ns_descr = "isolated";
}
}
// Do some best effort to emulate library-path support. It will not // work for dependencies. // // Note: null has a special meaning and must be preserved.
std::string library_path; // Empty string by default. if (library_path_j != nullptr && path != nullptr && path[0] != '/') {
ScopedUtfChars library_path_utf_chars(env, library_path_j);
library_path = library_path_utf_chars.c_str();
}
// native_bridge_namespaces are not supported for callers of this function. // This function will return nullptr in the case when application is running // on native bridge.
android_namespace_t* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
std::lock_guard<std::mutex> guard(g_namespaces_mutex);
NativeLoaderNamespace* ns = g_namespaces->FindNamespaceByClassLoader(env, class_loader); if (ns != nullptr && !ns->IsBridged()) { return ns->ToRawAndroidNamespace();
} return nullptr;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.