From 8a9b51e34f3769a5e3ea3a4383e3f00489088738 Mon Sep 17 00:00:00 2001 From: Martin Stjernholm Date: Tue, 30 Jan 2024 21:33:09 +0000 Subject: Refactorings to make more logic available at the top level in native_loader.cpp. - Make the code that determines the partition from the dex path available to code in native_loader.cpp, and rename it since it'll be applied to arbitrary paths, not just APK's. - Move the linker namespace constants to a header file. - Various other minor code cleanups. To prepare for a later CL that needs to access these things from OpenNativeLibrary. No functional changes. Test: atest libnativeloader_e2e_tests libnativeloader_test Bug: 237577392 Change-Id: Ifc762bf6d4664b2d477c4ed3af58f149fb4c1189 --- libnativeloader/library_namespaces.cpp | 183 +++++++++++++++------------------ 1 file changed, 84 insertions(+), 99 deletions(-) (limited to 'libnativeloader/library_namespaces.cpp') diff --git a/libnativeloader/library_namespaces.cpp b/libnativeloader/library_namespaces.cpp index 1e29f4e457..683e76247f 100644 --- a/libnativeloader/library_namespaces.cpp +++ b/libnativeloader/library_namespaces.cpp @@ -16,6 +16,8 @@ #if defined(ART_TARGET_ANDROID) +#define LOG_TAG "nativeloader" + #include "library_namespaces.h" #include @@ -25,14 +27,13 @@ #include #include -#include -#include -#include -#include -#include -#include -#include - +#include "android-base/file.h" +#include "android-base/logging.h" +#include "android-base/macros.h" +#include "android-base/result.h" +#include "android-base/stringprintf.h" +#include "android-base/strings.h" +#include "nativehelper/scoped_utf_chars.h" #include "nativeloader/dlext_namespaces.h" #include "public_libraries.h" #include "utils.h" @@ -43,19 +44,6 @@ namespace { constexpr const char* kApexPath = "/apex/"; -// The device may be configured to have the vendor libraries loaded to a separate namespace. -// For historical reasons this namespace was named sphal but effectively it is intended -// to use to load vendor libraries to separate namespace with controlled interface between -// vendor and system namespaces. -constexpr const char* kVendorNamespaceName = "sphal"; -// Similar to sphal namespace, product namespace provides some product libraries. -constexpr const char* kProductNamespaceName = "product"; - -// vndk namespace for unbundled vendor apps -constexpr const char* kVndkNamespaceName = "vndk"; -// vndk_product namespace for unbundled product apps -constexpr const char* kVndkProductNamespaceName = "vndk_product"; - // clns-XX is a linker namespace that is created for normal apps installed in // the data partition. To be specific, it is created for the app classloader. // When System.load() is called from a Java class that is loaded from the @@ -89,15 +77,8 @@ constexpr const char* kVendorLibPath = "/vendor/" LIB; // a symlink to the other. constexpr const char* kProductLibPath = "/product/" LIB ":/system/product/" LIB; -const std::regex kVendorDexPathRegex("(^|:)(/system)?/vendor/"); -const std::regex kProductDexPathRegex("(^|:)(/system)?/product/"); - -// Define origin partition of APK -using ApkOrigin = enum { - APK_ORIGIN_DEFAULT = 0, - APK_ORIGIN_VENDOR = 1, // Includes both /vendor and /system/vendor - APK_ORIGIN_PRODUCT = 2, // Includes both /product and /system/product -}; +const std::regex kVendorPathRegex("(^|:)(/system)?/vendor/"); +const std::regex kProductPathRegex("(^|:)(/system)?/product/"); jobject GetParentClassLoader(JNIEnv* env, jobject class_loader) { jclass class_loader_class = env->FindClass("java/lang/ClassLoader"); @@ -107,23 +88,22 @@ jobject GetParentClassLoader(JNIEnv* env, jobject class_loader) { return env->CallObjectMethod(class_loader, get_parent); } -ApkOrigin GetApkOriginFromDexPath(const std::string& dex_path) { - ApkOrigin apk_origin = APK_ORIGIN_DEFAULT; - if (std::regex_search(dex_path, kVendorDexPathRegex)) { - apk_origin = APK_ORIGIN_VENDOR; - } - if (std::regex_search(dex_path, kProductDexPathRegex)) { - LOG_ALWAYS_FATAL_IF(apk_origin == APK_ORIGIN_VENDOR, - "Dex path contains both vendor and product partition : %s", - dex_path.c_str()); +} // namespace - apk_origin = APK_ORIGIN_PRODUCT; +ApiDomain GetApiDomainFromPath(const std::string& path) { + ApiDomain api_domain = API_DOMAIN_DEFAULT; + if (std::regex_search(path, kVendorPathRegex)) { + api_domain = API_DOMAIN_VENDOR; } - return apk_origin; + if (is_product_treblelized() && std::regex_search(path, kProductPathRegex)) { + LOG_ALWAYS_FATAL_IF(api_domain == API_DOMAIN_VENDOR, + "Path matches both vendor and product partitions: %s", + path.c_str()); + api_domain = API_DOMAIN_PRODUCT; + } + return api_domain; } -} // namespace - void LibraryNamespaces::Initialize() { // Once public namespace is initialized there is no // point in running this code - it will have no effect @@ -170,7 +150,7 @@ static const std::string filter_public_libraries( } std::vector filtered; std::vector orig = android::base::Split(public_libraries, ":"); - for (const auto& lib : uses_libraries) { + for (const std::string& lib : uses_libraries) { if (std::find(orig.begin(), orig.end(), lib) != orig.end()) { filtered.emplace_back(lib); } @@ -178,32 +158,29 @@ static const std::string filter_public_libraries( return android::base::Join(filtered, ":"); } -Result LibraryNamespaces::Create(JNIEnv* env, uint32_t target_sdk_version, - jobject class_loader, bool is_shared, - jstring dex_path_j, - jstring java_library_path, - jstring java_permitted_path, - jstring uses_library_list) { +Result LibraryNamespaces::Create(JNIEnv* env, + uint32_t target_sdk_version, + jobject class_loader, + ApiDomain api_domain, + bool is_shared, + const std::string& dex_path, + jstring library_path_j, + jstring permitted_path_j, + jstring uses_library_list_j) { std::string library_path; // empty string by default. - std::string dex_path; - if (java_library_path != nullptr) { - ScopedUtfChars library_path_utf_chars(env, java_library_path); + if (library_path_j != nullptr) { + ScopedUtfChars library_path_utf_chars(env, library_path_j); library_path = library_path_utf_chars.c_str(); } - if (dex_path_j != nullptr) { - ScopedUtfChars dex_path_chars(env, dex_path_j); - dex_path = dex_path_chars.c_str(); - } - std::vector uses_libraries; - if (uses_library_list != nullptr) { - ScopedUtfChars names(env, uses_library_list); + if (uses_library_list_j != nullptr) { + ScopedUtfChars names(env, uses_library_list_j); uses_libraries = android::base::Split(names.c_str(), ":"); } else { - // uses_library_list could be nullptr when System.loadLibrary is called from a - // custom classloader. In that case, we don't know the list of public + // uses_library_list_j could be nullptr when System.loadLibrary is called + // from a custom classloader. In that case, we don't know the list of public // libraries because we don't know which apk the classloader is for. Only // choices we can have are 1) allowing all public libs (as before), or 2) // not allowing all but NDK libs. Here we take #1 because #2 would surprise @@ -214,8 +191,6 @@ Result LibraryNamespaces::Create(JNIEnv* env, uint32_t t uses_libraries.emplace_back(LIBRARY_ALL); } - ApkOrigin apk_origin = GetApkOriginFromDexPath(dex_path); - // (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. @@ -224,8 +199,8 @@ Result LibraryNamespaces::Create(JNIEnv* env, uint32_t t // under /data and /mnt/expand std::string permitted_path = kAlwaysPermittedDirectories; - if (java_permitted_path != nullptr) { - ScopedUtfChars path(env, java_permitted_path); + if (permitted_path_j != nullptr) { + ScopedUtfChars path(env, permitted_path_j); if (path.c_str() != nullptr && path.size() > 0) { permitted_path = permitted_path + ":" + path.c_str(); } @@ -236,13 +211,13 @@ Result LibraryNamespaces::Create(JNIEnv* env, uint32_t t std::string system_exposed_libraries = default_public_libraries(); std::string namespace_name = kClassloaderNamespaceName; - ApkOrigin unbundled_app_origin = APK_ORIGIN_DEFAULT; - const char* apk_origin_msg = "other apk"; // Only for debug logging. + ApiDomain unbundled_app_domain = API_DOMAIN_DEFAULT; + const char* api_domain_msg = "other apk"; // Only for debug logging. if (!is_shared) { - if (apk_origin == APK_ORIGIN_VENDOR) { - unbundled_app_origin = APK_ORIGIN_VENDOR; - apk_origin_msg = "unbundled vendor apk"; + if (api_domain == API_DOMAIN_VENDOR) { + unbundled_app_domain = API_DOMAIN_VENDOR; + api_domain_msg = "unbundled vendor apk"; // For vendor apks, give access to the vendor libs even though they are // treated as unbundled; the libs and apks are still bundled together in the @@ -255,9 +230,9 @@ Result LibraryNamespaces::Create(JNIEnv* env, uint32_t t // Different name is useful for debugging namespace_name = kVendorClassloaderNamespaceName; - } else if (apk_origin == APK_ORIGIN_PRODUCT && is_product_treblelized()) { - unbundled_app_origin = APK_ORIGIN_PRODUCT; - apk_origin_msg = "unbundled product apk"; + } else if (api_domain == API_DOMAIN_PRODUCT) { + unbundled_app_domain = API_DOMAIN_PRODUCT; + api_domain_msg = "unbundled product apk"; // Like for vendor apks, give access to the product libs since they are // bundled together in the same partition. @@ -287,20 +262,20 @@ Result LibraryNamespaces::Create(JNIEnv* env, uint32_t t "Configuring %s for %s %s. target_sdk_version=%u, uses_libraries=%s, library_path=%s, " "permitted_path=%s", namespace_name.c_str(), - apk_origin_msg, + api_domain_msg, dex_path.c_str(), static_cast(target_sdk_version), android::base::Join(uses_libraries, ':').c_str(), library_path.c_str(), permitted_path.c_str()); - if (unbundled_app_origin != APK_ORIGIN_VENDOR) { + if (unbundled_app_domain != API_DOMAIN_VENDOR) { // Extended public libraries are NOT available to unbundled vendor apks, but // they are to other apps, including those in system, system_ext, and // product partitions. The reason is that when GSI is used, the system // partition may get replaced, and then vendor apps may fail. It's fine for // product apps, because that partition isn't mounted in GSI tests. - auto libs = + const std::string libs = filter_public_libraries(target_sdk_version, uses_libraries, extended_public_libraries()); if (!libs.empty()) { ALOGD("Extending system_exposed_libraries: %s", libs.c_str()); @@ -320,27 +295,33 @@ Result LibraryNamespaces::Create(JNIEnv* env, uint32_t t bool also_used_as_anonymous = is_main_classloader; // Note: this function is executed with g_namespaces_mutex held, thus no // racing here. - auto app_ns = NativeLoaderNamespace::Create( - namespace_name, library_path, permitted_path, parent_ns, is_shared, - target_sdk_version < 24 /* is_exempt_list_enabled */, also_used_as_anonymous); + Result app_ns = + NativeLoaderNamespace::Create(namespace_name, + library_path, + permitted_path, + parent_ns, + is_shared, + target_sdk_version < 24 /* is_exempt_list_enabled */, + also_used_as_anonymous); if (!app_ns.ok()) { return app_ns.error(); } // ... and link to other namespaces to allow access to some public libraries bool is_bridged = app_ns->IsBridged(); - auto system_ns = NativeLoaderNamespace::GetSystemNamespace(is_bridged); + Result system_ns = NativeLoaderNamespace::GetSystemNamespace(is_bridged); if (!system_ns.ok()) { return system_ns.error(); } - auto linked = app_ns->Link(&system_ns.value(), system_exposed_libraries); + Result linked = app_ns->Link(&system_ns.value(), system_exposed_libraries); if (!linked.ok()) { return linked.error(); } for (const auto&[apex_ns_name, public_libs] : apex_public_libraries()) { - auto ns = NativeLoaderNamespace::GetExportedNamespace(apex_ns_name, is_bridged); + Result ns = + NativeLoaderNamespace::GetExportedNamespace(apex_ns_name, is_bridged); // Even if APEX namespace is visible, it may not be available to bridged. if (ns.ok()) { linked = app_ns->Link(&ns.value(), public_libs); @@ -351,8 +332,9 @@ Result LibraryNamespaces::Create(JNIEnv* env, uint32_t t } // Give access to VNDK-SP libraries from the 'vndk' namespace for unbundled vendor apps. - if (unbundled_app_origin == APK_ORIGIN_VENDOR && !vndksp_libraries_vendor().empty()) { - auto vndk_ns = NativeLoaderNamespace::GetExportedNamespace(kVndkNamespaceName, is_bridged); + if (unbundled_app_domain == API_DOMAIN_VENDOR && !vndksp_libraries_vendor().empty()) { + Result vndk_ns = + NativeLoaderNamespace::GetExportedNamespace(kVndkNamespaceName, is_bridged); if (vndk_ns.ok()) { linked = app_ns->Link(&vndk_ns.value(), vndksp_libraries_vendor()); if (!linked.ok()) { @@ -362,8 +344,9 @@ Result LibraryNamespaces::Create(JNIEnv* env, uint32_t t } // Give access to VNDK-SP libraries from the 'vndk_product' namespace for unbundled product apps. - if (unbundled_app_origin == APK_ORIGIN_PRODUCT && !vndksp_libraries_product().empty()) { - auto vndk_ns = NativeLoaderNamespace::GetExportedNamespace(kVndkProductNamespaceName, is_bridged); + if (unbundled_app_domain == API_DOMAIN_PRODUCT && !vndksp_libraries_product().empty()) { + Result vndk_ns = + NativeLoaderNamespace::GetExportedNamespace(kVndkProductNamespaceName, is_bridged); if (vndk_ns.ok()) { linked = app_ns->Link(&vndk_ns.value(), vndksp_libraries_product()); if (!linked.ok()) { @@ -373,11 +356,12 @@ Result LibraryNamespaces::Create(JNIEnv* env, uint32_t t } for (const std::string& each_jar_path : android::base::Split(dex_path, ":")) { - auto apex_ns_name = FindApexNamespaceName(each_jar_path); + Result apex_ns_name = FindApexNamespaceName(each_jar_path); if (apex_ns_name.ok()) { - const auto& jni_libs = apex_jni_libraries(*apex_ns_name); + const std::string& jni_libs = apex_jni_libraries(*apex_ns_name); if (jni_libs != "") { - auto apex_ns = NativeLoaderNamespace::GetExportedNamespace(*apex_ns_name, is_bridged); + Result apex_ns = + NativeLoaderNamespace::GetExportedNamespace(*apex_ns_name, is_bridged); if (apex_ns.ok()) { linked = app_ns->Link(&apex_ns.value(), jni_libs); if (!linked.ok()) { @@ -388,12 +372,13 @@ Result LibraryNamespaces::Create(JNIEnv* env, uint32_t t } } - auto vendor_libs = filter_public_libraries(target_sdk_version, uses_libraries, - vendor_public_libraries()); + const std::string vendor_libs = + filter_public_libraries(target_sdk_version, uses_libraries, vendor_public_libraries()); if (!vendor_libs.empty()) { - auto vendor_ns = NativeLoaderNamespace::GetExportedNamespace(kVendorNamespaceName, is_bridged); + Result vendor_ns = + NativeLoaderNamespace::GetExportedNamespace(kVendorNamespaceName, is_bridged); // when vendor_ns is not configured, link to the system namespace - auto target_ns = vendor_ns.ok() ? vendor_ns : system_ns; + Result target_ns = vendor_ns.ok() ? vendor_ns : system_ns; if (target_ns.ok()) { linked = app_ns->Link(&target_ns.value(), vendor_libs); if (!linked.ok()) { @@ -402,10 +387,10 @@ Result LibraryNamespaces::Create(JNIEnv* env, uint32_t t } } - auto product_libs = filter_public_libraries(target_sdk_version, uses_libraries, - product_public_libraries()); + const std::string product_libs = + filter_public_libraries(target_sdk_version, uses_libraries, product_public_libraries()); if (!product_libs.empty()) { - auto target_ns = system_ns; + Result target_ns = system_ns; if (is_product_treblelized()) { target_ns = NativeLoaderNamespace::GetExportedNamespace(kProductNamespaceName, is_bridged); } @@ -422,8 +407,8 @@ Result LibraryNamespaces::Create(JNIEnv* env, uint32_t t } } - auto& emplaced = namespaces_.emplace_back( - std::make_pair(env->NewWeakGlobalRef(class_loader), *app_ns)); + std::pair& emplaced = + namespaces_.emplace_back(std::make_pair(env->NewWeakGlobalRef(class_loader), *app_ns)); if (is_main_classloader) { app_main_namespace_ = &emplaced.second; } -- cgit v1.2.3-59-g8ed1b