diff options
Diffstat (limited to 'libnativeloader')
34 files changed, 1572 insertions, 363 deletions
diff --git a/libnativeloader/Android.bp b/libnativeloader/Android.bp index 0e6389267a..96f56775f6 100644 --- a/libnativeloader/Android.bp +++ b/libnativeloader/Android.bp @@ -27,6 +27,7 @@ art_cc_library { apex_available: [ "com.android.art", "com.android.art.debug", + "test_broken_com.android.art", ], host_supported: true, srcs: [ @@ -64,7 +65,7 @@ art_cc_library { "libdl_android", ], static_libs: [ - "PlatformProperties", + "libPlatformProperties", ], }, }, @@ -176,19 +177,6 @@ art_cc_test { }, }, - // Support multilib variants (using different suffix per sub-architecture), which is needed on - // build targets with secondary architectures, as the CTS test suite packaging logic flattens - // all test artifacts into a single `testcases` directory. - compile_multilib: "both", - multilib: { - lib32: { - suffix: "32", - }, - lib64: { - suffix: "64", - }, - }, - // Added to CTS for API coverage of libnativeloader which is backed by the // ART module. test_config_template: ":art-gtests-target-standalone-cts-template", diff --git a/libnativeloader/OWNERS b/libnativeloader/OWNERS index f7356530ab..87f91426c8 100644 --- a/libnativeloader/OWNERS +++ b/libnativeloader/OWNERS @@ -1,6 +1,6 @@ -dimitry@google.com +# Bug component: 86431 +mast@google.com jiyong@google.com ngeoffray@google.com oth@google.com -mast@google.com rpl@google.com diff --git a/libnativeloader/README.md b/libnativeloader/README.md index c5ace61ba5..919feff8db 100644 --- a/libnativeloader/README.md +++ b/libnativeloader/README.md @@ -10,11 +10,11 @@ by the platform. The most typical use case of this library is calling `System.loadLibrary(name)`. When the method is called, the ART runtime delegates the call to this library -along with the reference to the classloader where the call was made. Then this -library finds the linker namespace (named `classloader-namespace`) that is -associated with the given classloader, and tries to load the requested library -from the namespace. The actual searching, loading, and linking of the library -is performed by the dynamic linker. +along with the reference to the classloader where the call was made. Then this +library finds the linker namespace (typically with the name `clns-` followed by +a number to make it unique) that is associated with the given classloader, and +tries to load the requested library from that namespace. The actual searching, +loading, and linking of the library is performed by the dynamic linker. The linker namespace is created when an APK is loaded into the process, and is associated with the classloader that loaded the APK. The linker namespace is diff --git a/libnativeloader/libnativeloader.map.txt b/libnativeloader/libnativeloader.map.txt index 59f457c04c..8c0fbddb4e 100644 --- a/libnativeloader/libnativeloader.map.txt +++ b/libnativeloader/libnativeloader.map.txt @@ -20,13 +20,13 @@ # that defines the exported interface. Please keep in sync with this list. LIBNATIVELOADER_1 { global: - OpenNativeLibrary; - CloseNativeLibrary; - OpenNativeLibraryInNamespace; - FindNamespaceByClassLoader; - FindNativeLoaderNamespaceByClassLoader; - CreateClassLoaderNamespace; - NativeLoaderFreeErrorMessage; + OpenNativeLibrary; # apex + CloseNativeLibrary; # apex + OpenNativeLibraryInNamespace; # apex + FindNamespaceByClassLoader; # apex + FindNativeLoaderNamespaceByClassLoader; # apex + CreateClassLoaderNamespace; # apex + NativeLoaderFreeErrorMessage; # apex local: *; }; diff --git a/libnativeloader/library_namespaces.cpp b/libnativeloader/library_namespaces.cpp index f31c4302a4..9aeebf38ad 100644 --- a/libnativeloader/library_namespaces.cpp +++ b/libnativeloader/library_namespaces.cpp @@ -30,6 +30,7 @@ #include <android-base/macros.h> #include <android-base/result.h> #include <android-base/strings.h> +#include <android-base/stringprintf.h> #include <nativehelper/scoped_utf_chars.h> #include "nativeloader/dlext_namespaces.h" @@ -55,24 +56,26 @@ constexpr const char* kVndkNamespaceName = "vndk"; // vndk_product namespace for unbundled product apps constexpr const char* kVndkProductNamespaceName = "vndk_product"; -// classloader-namespace is a linker namespace that is created for the loaded -// app. To be specific, it is created for the app classloader. When -// System.load() is called from a Java class that is loaded from the -// classloader, the classloader-namespace namespace associated with that -// classloader is selected for dlopen. The namespace is configured so that its -// search path is set to the app-local JNI directory and it is linked to the -// system namespace with the names of libs listed in the public.libraries.txt. -// This way an app can only load its own JNI libraries along with the public libs. -constexpr const char* kClassloaderNamespaceName = "classloader-namespace"; -// Same thing for vendor APKs. -constexpr const char* kVendorClassloaderNamespaceName = "vendor-classloader-namespace"; -// If the namespace is shared then add this suffix to form -// "classloader-namespace-shared" or "vendor-classloader-namespace-shared", -// respectively. A shared namespace (cf. ANDROID_NAMESPACE_TYPE_SHARED) has +// 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 +// classloader, the clns namespace associated with that classloader is selected +// for dlopen. The namespace is configured so that its search path is set to the +// app-local JNI directory and it is linked to the system namespace with the +// names of libs listed in the public.libraries.txt and other public libraries. +// This way an app can only load its own JNI libraries along with the public +// libs. +constexpr const char* kClassloaderNamespaceName = "clns"; +// Same thing for unbundled APKs in the vendor partition. +constexpr const char* kVendorClassloaderNamespaceName = "vendor-clns"; +// Same thing for unbundled APKs in the product partition. +constexpr const char* kProductClassloaderNamespaceName = "product-clns"; +// If the namespace is shared then add this suffix to help identify it in debug +// messages. A shared namespace (cf. ANDROID_NAMESPACE_TYPE_SHARED) has // inherited all the libraries of the parent classloader namespace, or the -// system namespace for the main app classloader. It is used to give full -// access to the platform libraries for apps bundled in the system image, -// including their later updates installed in /data. +// system namespace for the main app classloader. It is used to give full access +// to the platform libraries for apps bundled in the system image, including +// their later updates installed in /data. constexpr const char* kSharedNamespaceSuffix = "-shared"; // (http://b/27588281) This is a workaround for apps using custom classloaders and calling @@ -81,16 +84,19 @@ constexpr const char* kSharedNamespaceSuffix = "-shared"; constexpr const char* kAlwaysPermittedDirectories = "/data:/mnt/expand"; constexpr const char* kVendorLibPath = "/vendor/" LIB; +// TODO(mast): It's unlikely that both paths are necessary for kProductLibPath +// below, because they can't be two separate directories - either one has to be +// a symlink to the other. constexpr const char* kProductLibPath = "/product/" LIB ":/system/product/" LIB; -const std::regex kVendorDexPathRegex("(^|:)/vendor/"); +const std::regex kVendorDexPathRegex("(^|:)(/system)?/vendor/"); const std::regex kProductDexPathRegex("(^|:)(/system)?/product/"); -// Define origin of APK if it is from vendor partition or product partition +// Define origin partition of APK using ApkOrigin = enum { APK_ORIGIN_DEFAULT = 0, - APK_ORIGIN_VENDOR = 1, - APK_ORIGIN_PRODUCT = 2, + APK_ORIGIN_VENDOR = 1, // Includes both /vendor and /system/vendor + APK_ORIGIN_PRODUCT = 2, // Includes both /product and /system/product }; jobject GetParentClassLoader(JNIEnv* env, jobject class_loader) { @@ -231,51 +237,38 @@ Result<NativeLoaderNamespace*> 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; - if ((apk_origin == APK_ORIGIN_VENDOR || - (apk_origin == APK_ORIGIN_PRODUCT && - is_product_vndk_version_defined())) && - !is_shared) { - unbundled_app_origin = apk_origin; - // For vendor / product apks, give access to the vendor / product lib even though - // they are treated as unbundled; the libs and apks are still bundled - // together in the vendor / product partition. - const char* origin_partition; - const char* origin_lib_path; - const char* llndk_libraries; - - switch (apk_origin) { - case APK_ORIGIN_VENDOR: - origin_partition = "vendor"; - origin_lib_path = kVendorLibPath; - llndk_libraries = llndk_libraries_vendor().c_str(); - break; - case APK_ORIGIN_PRODUCT: - origin_partition = "product"; - origin_lib_path = kProductLibPath; - llndk_libraries = llndk_libraries_product().c_str(); - break; - default: - origin_partition = "unknown"; - origin_lib_path = ""; - llndk_libraries = ""; - } - library_path = library_path + ":" + origin_lib_path; - permitted_path = permitted_path + ":" + origin_lib_path; - - // Also give access to LLNDK libraries since they are available to vendor or product - system_exposed_libraries = system_exposed_libraries + ":" + llndk_libraries; - - // Different name is useful for debugging - namespace_name = kVendorClassloaderNamespaceName; - ALOGD("classloader namespace configured for unbundled %s apk. library_path=%s", - origin_partition, library_path.c_str()); - } else { - auto libs = filter_public_libraries(target_sdk_version, uses_libraries, - extended_public_libraries()); - // extended public libraries are NOT available to vendor apks, otherwise it - // would be system->vendor violation. - if (!libs.empty()) { - system_exposed_libraries = system_exposed_libraries + ':' + libs; + const char* apk_origin_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"; + + // 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 + // vendor partition. + library_path = library_path + ':' + kVendorLibPath; + permitted_path = permitted_path + ':' + kVendorLibPath; + + // Also give access to LLNDK libraries since they are available to vendor. + system_exposed_libraries = system_exposed_libraries + ':' + llndk_libraries_vendor(); + + // Different name is useful for debugging + namespace_name = kVendorClassloaderNamespaceName; + } else if (apk_origin == APK_ORIGIN_PRODUCT && is_product_vndk_version_defined()) { + unbundled_app_origin = APK_ORIGIN_PRODUCT; + apk_origin_msg = "unbundled product apk"; + + // Like for vendor apks, give access to the product libs since they are + // bundled together in the same partition. + library_path = library_path + ':' + kProductLibPath; + permitted_path = permitted_path + ':' + kProductLibPath; + + // Also give access to LLNDK libraries since they are available to product. + system_exposed_libraries = system_exposed_libraries + ':' + llndk_libraries_product(); + + // Different name is useful for debugging + namespace_name = kProductClassloaderNamespaceName; } } @@ -285,6 +278,36 @@ Result<NativeLoaderNamespace*> LibraryNamespaces::Create(JNIEnv* env, uint32_t t namespace_name = namespace_name + kSharedNamespaceSuffix; } + // Append a unique number to the namespace name, to tell them apart when + // debugging linker issues, e.g. with debug.ld.all set to "dlopen,dlerror". + static int clns_count = 0; + namespace_name = android::base::StringPrintf("%s-%d", namespace_name.c_str(), ++clns_count); + + ALOGD( + "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, + dex_path.c_str(), + static_cast<unsigned>(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) { + // 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 = + filter_public_libraries(target_sdk_version, uses_libraries, extended_public_libraries()); + if (!libs.empty()) { + ALOGD("Extending system_exposed_libraries: %s", libs.c_str()); + system_exposed_libraries = system_exposed_libraries + ':' + libs; + } + } + // Create the app namespace NativeLoaderNamespace* parent_ns = FindParentNamespaceByClassLoader(env, class_loader); // Heuristic: the first classloader with non-empty library_path is assumed to diff --git a/libnativeloader/native_loader_test.cpp b/libnativeloader/native_loader_test.cpp index 1dc778abcd..6c0c8b17a7 100644 --- a/libnativeloader/native_loader_test.cpp +++ b/libnativeloader/native_loader_test.cpp @@ -31,10 +31,10 @@ namespace android { namespace nativeloader { using ::testing::Eq; -using ::testing::MatchesRegex; using ::testing::NotNull; +using ::testing::StartsWith; using ::testing::StrEq; -using internal::ConfigEntry; +using internal::ConfigEntry; // NOLINT - ConfigEntry is actually used using internal::ParseApexLibrariesConfig; using internal::ParseConfig; @@ -69,7 +69,7 @@ class NativeLoaderTest : public ::testing::TestWithParam<bool> { void SetExpectations() { std::vector<std::string> default_public_libs = android::base::Split(preloadable_public_libraries(), ":"); - for (auto l : default_public_libs) { + for (const std::string& l : default_public_libs) { EXPECT_CALL(*mock, mock_dlopen_ext(false, StrEq(l.c_str()), RTLD_NOW | RTLD_NODELETE, NotNull())) .WillOnce(Return(any_nonnull)); @@ -168,13 +168,16 @@ INSTANTIATE_TEST_SUITE_P(NativeLoaderTests, NativeLoaderTest, testing::Bool()); ///////////////////////////////////////////////////////////////// -std::string default_public_and_extended_libraries() { - std::string public_libs = default_public_libraries(); - std::string ext_libs = extended_public_libraries(); +std::string append_extended_libraries(const std::string& libs) { + const std::string& ext_libs = extended_public_libraries(); if (!ext_libs.empty()) { - public_libs = public_libs + ":" + ext_libs; + return libs + ":" + ext_libs; } - return public_libs; + return libs; +} + +std::string default_public_and_extended_libraries() { + return append_extended_libraries(default_public_libraries()); } class NativeLoaderTest_Create : public NativeLoaderTest { @@ -189,7 +192,7 @@ class NativeLoaderTest_Create : public NativeLoaderTest { std::string permitted_path = "/data/app/foo/" LIB_DIR; // expected output (.. for the default test inputs) - std::string expected_namespace_name = "classloader-namespace"; + std::string expected_namespace_prefix = "clns"; uint64_t expected_namespace_flags = ANDROID_NAMESPACE_TYPE_ISOLATED | ANDROID_NAMESPACE_TYPE_ALSO_USED_AS_ANONYMOUS; std::string expected_library_path = library_path; @@ -225,7 +228,7 @@ class NativeLoaderTest_Create : public NativeLoaderTest { EXPECT_CALL(*mock, NativeBridgeInitialized()).Times(testing::AnyNumber()); EXPECT_CALL(*mock, mock_create_namespace( - Eq(IsBridged()), MatchesRegex(expected_namespace_name), nullptr, + Eq(IsBridged()), StartsWith(expected_namespace_prefix + "-"), nullptr, StrEq(expected_library_path), expected_namespace_flags, StrEq(expected_permitted_path), NsEq(expected_parent_namespace.c_str()))) .WillOnce(Return(TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE(dex_path.c_str())))); @@ -320,7 +323,7 @@ TEST_P(NativeLoaderTest_Create, BundledSystemApp) { dex_path = "/system/app/foo/foo.apk"; is_shared = true; - expected_namespace_name = "classloader-namespace-shared"; + expected_namespace_prefix = "clns-shared"; expected_namespace_flags |= ANDROID_NAMESPACE_TYPE_SHARED; SetExpectations(); RunTest(); @@ -330,7 +333,7 @@ TEST_P(NativeLoaderTest_Create, BundledVendorApp) { dex_path = "/vendor/app/foo/foo.apk"; is_shared = true; - expected_namespace_name = "classloader-namespace-shared"; + expected_namespace_prefix = "clns-shared"; expected_namespace_flags |= ANDROID_NAMESPACE_TYPE_SHARED; SetExpectations(); RunTest(); @@ -340,12 +343,12 @@ TEST_P(NativeLoaderTest_Create, UnbundledVendorApp) { dex_path = "/vendor/app/foo/foo.apk"; is_shared = false; - expected_namespace_name = "vendor-classloader-namespace"; + expected_namespace_prefix = "vendor-clns"; expected_library_path = expected_library_path + ":/vendor/" LIB_DIR; expected_permitted_path = expected_permitted_path + ":/vendor/" LIB_DIR; expected_shared_libs_to_platform_ns = default_public_libraries() + ":" + llndk_libraries_vendor(); - expected_link_with_vndk_ns = !get_vndk_version(/*is_product_vndk=*/false).empty(); + expected_link_with_vndk_ns = true; SetExpectations(); RunTest(); } @@ -354,7 +357,7 @@ TEST_P(NativeLoaderTest_Create, BundledProductApp) { dex_path = "/product/app/foo/foo.apk"; is_shared = true; - expected_namespace_name = "classloader-namespace-shared"; + expected_namespace_prefix = "clns-shared"; expected_namespace_flags |= ANDROID_NAMESPACE_TYPE_SHARED; SetExpectations(); RunTest(); @@ -364,7 +367,7 @@ TEST_P(NativeLoaderTest_Create, SystemServerWithApexJars) { dex_path = "/system/framework/services.jar:/apex/com.android.conscrypt/javalib/service-foo.jar"; is_shared = true; - expected_namespace_name = "classloader-namespace-shared"; + expected_namespace_prefix = "clns-shared"; expected_namespace_flags |= ANDROID_NAMESPACE_TYPE_SHARED; expected_link_with_conscrypt_ns = true; SetExpectations(); @@ -376,28 +379,13 @@ TEST_P(NativeLoaderTest_Create, UnbundledProductApp) { is_shared = false; if (is_product_vndk_version_defined()) { - expected_namespace_name = "(vendor|product)-classloader-namespace"; + expected_namespace_prefix = "product-clns"; expected_library_path = expected_library_path + ":/product/" LIB_DIR ":/system/product/" LIB_DIR; expected_permitted_path = expected_permitted_path + ":/product/" LIB_DIR ":/system/product/" LIB_DIR; - expected_link_with_vndk_product_ns = true; - - // The handling of extended libraries for product apps changed in the - // M-2022-10 release of the ART module (https://r.android.com/2194871). - // Since this test is in CTS for T, we need to accept both new and old - // behaviour, i.e. with and without the extended public libraries appended - // at the end. Skip the EXPECT_CALL in - // NativeLoaderTest_Create::SetExpectations and create a more lenient - // variant of it here. - expected_link_with_platform_ns = false; expected_shared_libs_to_platform_ns = - default_public_libraries() + ":" + llndk_libraries_product(); - EXPECT_CALL(*mock, - mock_link_namespaces(Eq(IsBridged()), - _, - NsEq("system"), - ::testing::StartsWith(expected_shared_libs_to_platform_ns))) - .WillOnce(Return(true)); + append_extended_libraries(default_public_libraries() + ":" + llndk_libraries_product()); + expected_link_with_vndk_product_ns = true; } SetExpectations(); RunTest(); @@ -429,7 +417,7 @@ TEST_P(NativeLoaderTest_Create, TwoApks) { const std::string second_app_permitted_path = "/data/app/bar/" LIB_DIR; const std::string expected_second_app_permitted_path = std::string("/data:/mnt/expand:") + second_app_permitted_path; - const std::string expected_second_app_parent_namespace = "classloader-namespace"; + const std::string expected_second_app_parent_namespace = "clns"; // no ALSO_USED_AS_ANONYMOUS const uint64_t expected_second_namespace_flags = ANDROID_NAMESPACE_TYPE_ISOLATED; @@ -442,7 +430,7 @@ TEST_P(NativeLoaderTest_Create, TwoApks) { // namespace for the second app is created. Its parent is set to the namespace // of the first app. EXPECT_CALL(*mock, mock_create_namespace( - Eq(IsBridged()), StrEq(expected_namespace_name), nullptr, + Eq(IsBridged()), StartsWith(expected_namespace_prefix + "-"), nullptr, StrEq(second_app_library_path), expected_second_namespace_flags, StrEq(expected_second_app_permitted_path), NsEq(dex_path.c_str()))) .WillOnce(Return(TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE(second_app_dex_path.c_str())))); diff --git a/libnativeloader/native_loader_test.h b/libnativeloader/native_loader_test.h index 5c51f00e82..30b2f84cd2 100644 --- a/libnativeloader/native_loader_test.h +++ b/libnativeloader/native_loader_test.h @@ -42,7 +42,7 @@ class Platform { // Instead of having two set of mock APIs for the two, define only one set with an additional // argument 'bool bridged' to identify the context (i.e., called for libdl_android or // libnativebridge). - typedef char* mock_namespace_handle; + using mock_namespace_handle = char*; virtual bool mock_init_anonymous_namespace(bool bridged, const char* sonames, const char* search_paths) = 0; virtual mock_namespace_handle mock_create_namespace( diff --git a/libnativeloader/public_libraries.cpp b/libnativeloader/public_libraries.cpp index 433a9095ef..896c5c7106 100644 --- a/libnativeloader/public_libraries.cpp +++ b/libnativeloader/public_libraries.cpp @@ -46,7 +46,6 @@ using android::base::Result; using internal::ConfigEntry; using internal::ParseConfig; using internal::ParseApexLibrariesConfig; -using std::literals::string_literals::operator""s; namespace { @@ -117,7 +116,7 @@ void ReadExtensionLibraries(const char* dirname, std::vector<std::string>* sonam if (android::base::ConsumePrefix(&fn, kExtendedPublicLibrariesFilePrefix) && android::base::ConsumeSuffix(&fn, kExtendedPublicLibrariesFileSuffix)) { const std::string company_name(fn); - const std::string config_file_path = dirname + "/"s + filename; + const std::string config_file_path = std::string(dirname) + std::string("/") + filename; LOG_ALWAYS_FATAL_IF( company_name.empty(), "Error extracting company name from public native library list file path \"%s\"", @@ -129,8 +128,11 @@ void ReadExtensionLibraries(const char* dirname, std::vector<std::string>* sonam android::base::EndsWith(entry.soname, "." + company_name + ".so")) { return true; } else { - return Errorf("Library name \"{}\" does not end with the company name {}.", - entry.soname, company_name); + return Errorf( + "Library name \"{}\" does not start with \"lib\" and/or " + "does not end with the company name \"{}\".", + entry.soname, + company_name); } }); if (ret.ok()) { @@ -161,28 +163,36 @@ static std::string InitDefaultPublicLibraries(bool for_preload) { } // If this is for preloading libs, don't remove the libs from APEXes. - if (for_preload) { - return android::base::Join(*sonames, ':'); + if (!for_preload) { + // Remove the public libs provided by apexes because these libs are available + // from apex namespaces. + for (const auto& p : apex_public_libraries()) { + auto public_libs = base::Split(p.second, ":"); + sonames->erase(std::remove_if(sonames->begin(), + sonames->end(), + [&public_libs](const std::string& v) { + return std::find(public_libs.begin(), public_libs.end(), v) != + public_libs.end(); + }), + sonames->end()); + } } - // Remove the public libs provided by apexes because these libs are available - // from apex namespaces. - for (const auto& p : apex_public_libraries()) { - auto public_libs = base::Split(p.second, ":"); - sonames->erase(std::remove_if(sonames->begin(), sonames->end(), [&public_libs](const std::string& v) { - return std::find(public_libs.begin(), public_libs.end(), v) != public_libs.end(); - }), sonames->end()); - } - return android::base::Join(*sonames, ':'); + std::string libs = android::base::Join(*sonames, ':'); + ALOGD("InitDefaultPublicLibraries for_preload=%d: %s", for_preload, libs.c_str()); + return libs; } static std::string InitVendorPublicLibraries() { // This file is optional, quietly ignore if the file does not exist. auto sonames = ReadConfig(kVendorPublicLibrariesFile, always_true); if (!sonames.ok()) { + ALOGI("InitVendorPublicLibraries skipped: %s", sonames.error().message().c_str()); return ""; } - return android::base::Join(*sonames, ':'); + std::string libs = android::base::Join(*sonames, ':'); + ALOGD("InitVendorPublicLibraries: %s", libs.c_str()); + return libs; } // If ro.product.vndk.version is defined, /product/etc/public.libraries-<companyname>.txt contains @@ -193,7 +203,9 @@ static std::string InitProductPublicLibraries() { if (is_product_vndk_version_defined()) { ReadExtensionLibraries("/product/etc", &sonames); } - return android::base::Join(sonames, ':'); + std::string libs = android::base::Join(sonames, ':'); + ALOGD("InitProductPublicLibraries: %s", libs.c_str()); + return libs; } // read /system/etc/public.libraries-<companyname>.txt, @@ -208,13 +220,12 @@ static std::string InitExtendedPublicLibraries() { if (!is_product_vndk_version_defined()) { ReadExtensionLibraries("/product/etc", &sonames); } - return android::base::Join(sonames, ':'); + std::string libs = android::base::Join(sonames, ':'); + ALOGD("InitExtendedPublicLibraries: %s", libs.c_str()); + return libs; } static std::string InitLlndkLibrariesVendor() { - if (get_vndk_version(/*is_product_vndk=*/false).empty()) { - return ""; - } std::string config_file = kLlndkLibrariesFile; InsertVndkVersionStr(&config_file, false); auto sonames = ReadConfig(config_file, always_true); @@ -222,11 +233,14 @@ static std::string InitLlndkLibrariesVendor() { LOG_ALWAYS_FATAL("%s: %s", config_file.c_str(), sonames.error().message().c_str()); return ""; } - return android::base::Join(*sonames, ':'); + std::string libs = android::base::Join(*sonames, ':'); + ALOGD("InitLlndkLibrariesVendor: %s", libs.c_str()); + return libs; } static std::string InitLlndkLibrariesProduct() { if (!is_product_vndk_version_defined()) { + ALOGD("InitLlndkLibrariesProduct: No product VNDK version defined"); return ""; } std::string config_file = kLlndkLibrariesFile; @@ -236,13 +250,12 @@ static std::string InitLlndkLibrariesProduct() { LOG_ALWAYS_FATAL("%s: %s", config_file.c_str(), sonames.error().message().c_str()); return ""; } - return android::base::Join(*sonames, ':'); + std::string libs = android::base::Join(*sonames, ':'); + ALOGD("InitLlndkLibrariesProduct: %s", libs.c_str()); + return libs; } static std::string InitVndkspLibrariesVendor() { - if (get_vndk_version(/*is_product_vndk=*/false).empty()) { - return ""; - } std::string config_file = kVndkLibrariesFile; InsertVndkVersionStr(&config_file, false); auto sonames = ReadConfig(config_file, always_true); @@ -250,11 +263,14 @@ static std::string InitVndkspLibrariesVendor() { LOG_ALWAYS_FATAL("%s", sonames.error().message().c_str()); return ""; } - return android::base::Join(*sonames, ':'); + std::string libs = android::base::Join(*sonames, ':'); + ALOGD("InitVndkspLibrariesVendor: %s", libs.c_str()); + return libs; } static std::string InitVndkspLibrariesProduct() { if (!is_product_vndk_version_defined()) { + ALOGD("InitVndkspLibrariesProduct: No product VNDK version defined"); return ""; } std::string config_file = kVndkLibrariesFile; @@ -264,20 +280,33 @@ static std::string InitVndkspLibrariesProduct() { LOG_ALWAYS_FATAL("%s", sonames.error().message().c_str()); return ""; } - return android::base::Join(*sonames, ':'); + std::string libs = android::base::Join(*sonames, ':'); + ALOGD("InitVndkspLibrariesProduct: %s", libs.c_str()); + return libs; } static std::map<std::string, std::string> InitApexLibraries(const std::string& tag) { std::string file_content; if (!base::ReadFileToString(kApexLibrariesConfigFile, &file_content)) { // config is optional + ALOGI("InitApexLibraries skipped: %s", strerror(errno)); return {}; } - auto config = ParseApexLibrariesConfig(file_content, tag); + Result<std::map<std::string, std::string>> config = ParseApexLibrariesConfig(file_content, tag); if (!config.ok()) { LOG_ALWAYS_FATAL("%s: %s", kApexLibrariesConfigFile, config.error().message().c_str()); return {}; } + ALOGD("InitApexLibraries:\n %s", + [&config]() { + std::vector<std::string> lib_list; + lib_list.reserve(config->size()); + for (std::pair<std::string, std::string> elem : *config) { + lib_list.emplace_back(elem.first + ": " + elem.second); + } + return android::base::Join(lib_list, "\n "); + }() + .c_str()); return *config; } @@ -429,6 +458,12 @@ Result<std::vector<std::string>> ParseConfig( if (entry.bitness == ONLY_64) continue; #endif + // TODO(b/206676167): Remove this check when renderscript is officially removed. +#if defined(__riscv) + // skip renderscript lib on riscv target + if (entry.soname == "libRS.so") continue; +#endif + Result<bool> ret = filter_fn(entry); if (!ret.ok()) { return ret.error(); diff --git a/libnativeloader/test/Android.bp b/libnativeloader/test/Android.bp index fb9ae0d9d3..95b9b886dd 100644 --- a/libnativeloader/test/Android.bp +++ b/libnativeloader/test/Android.bp @@ -23,58 +23,179 @@ package { default_applicable_licenses: ["art_license"], } +// A native library that goes into /system or /system_ext and that depends on +// a non-public library that is linked from the system namespace. cc_library { - name: "libfoo.oem1", - srcs: ["test.cpp"], - cflags: ["-DLIBNAME=\"libfoo.oem1.so\""], - shared_libs: [ - "libbase", - ], + name: "libsystem_testlib", + min_sdk_version: "31", + stl: "libc++_static", + shared_libs: ["liblog"], + // It's difficult to add a shared_lib dependency on a non-public library + // here, so it dlopens one instead. + srcs: ["libsystem_testlib.cc"], } +// A native library that goes into /product. cc_library { - name: "libbar.oem1", - srcs: ["test.cpp"], - cflags: ["-DLIBNAME=\"libbar.oem1.so\""], - shared_libs: [ - "libbase", - ], + name: "libproduct_testlib", + min_sdk_version: "31", + stl: "none", + srcs: [], } +// A native library that goes into /vendor. cc_library { - name: "libfoo.oem2", - srcs: ["test.cpp"], - cflags: ["-DLIBNAME=\"libfoo.oem2.so\""], - shared_libs: [ - "libbase", + name: "libvendor_testlib", + min_sdk_version: "31", + stl: "none", + srcs: [], +} + +// This app is just an intermediate container to be able to include the .so +// library in the host test. It's not actually installed or started. +android_test_helper_app { + name: "library_container_app", + defaults: ["art_module_source_build_java_defaults"], + min_sdk_version: "31", + manifest: "library_container_app_manifest.xml", + compile_multilib: "both", + jni_libs: [ + "libsystem_testlib", + "libproduct_testlib", + "libvendor_testlib", ], } -cc_library { - name: "libbar.oem2", - srcs: ["test.cpp"], - cflags: ["-DLIBNAME=\"libbar.oem2.so\""], - shared_libs: [ - "libbase", +java_library { + name: "loadlibrarytest_test_utils", + sdk_version: "31", + static_libs: [ + "androidx.test.ext.junit", + "androidx.test.ext.truth", ], + srcs: ["src/android/test/lib/TestUtils.java"], } -cc_library { - name: "libfoo.product1", - srcs: ["test.cpp"], - cflags: ["-DLIBNAME=\"libfoo.product1.so\""], +// Test fixture that represents a shared library in /system/framework. +java_library { + name: "libnativeloader_system_shared_lib", + sdk_version: "31", + installable: true, + srcs: ["src/android/test/systemsharedlib/SystemSharedLib.java"], +} + +// Test fixture that represents a shared library in /system_ext/framework. +java_library { + name: "libnativeloader_system_ext_shared_lib", + sdk_version: "31", + installable: true, + srcs: ["src/android/test/systemextsharedlib/SystemExtSharedLib.java"], +} + +// Test fixture that represents a shared library in /product/framework. +java_library { + name: "libnativeloader_product_shared_lib", product_specific: true, - shared_libs: [ - "libbase", + sdk_version: "31", + installable: true, + srcs: ["src/android/test/productsharedlib/ProductSharedLib.java"], +} + +// Test fixture that represents a shared library in /vendor/framework. +java_library { + name: "libnativeloader_vendor_shared_lib", + vendor: true, + sdk_version: "31", + installable: true, + srcs: ["src/android/test/vendorsharedlib/VendorSharedLib.java"], +} + +java_defaults { + name: "loadlibrarytest_app_defaults", + defaults: ["art_module_source_build_java_defaults"], + sdk_version: "31", + static_libs: [ + "androidx.test.ext.junit", + "androidx.test.rules", + "loadlibrarytest_test_utils", + ], + libs: [ + "libnativeloader_system_shared_lib", + "libnativeloader_system_ext_shared_lib", + "libnativeloader_product_shared_lib", + "libnativeloader_vendor_shared_lib", ], } -cc_library { - name: "libbar.product1", - srcs: ["test.cpp"], - cflags: ["-DLIBNAME=\"libbar.product1.so\""], +android_test_helper_app { + name: "loadlibrarytest_system_priv_app", + defaults: ["loadlibrarytest_app_defaults"], + manifest: "loadlibrarytest_system_priv_app_manifest.xml", + // /system/priv-app currently reuses the same test as /system/app. + srcs: ["src/android/test/app/SystemAppTest.java"], +} + +android_test_helper_app { + name: "loadlibrarytest_system_app", + defaults: ["loadlibrarytest_app_defaults"], + manifest: "loadlibrarytest_system_app_manifest.xml", + srcs: ["src/android/test/app/SystemAppTest.java"], +} + +android_test_helper_app { + name: "loadlibrarytest_system_ext_app", + defaults: ["loadlibrarytest_app_defaults"], + system_ext_specific: true, + manifest: "loadlibrarytest_system_ext_app_manifest.xml", + // /system_ext should behave the same as /system, so use the same test class there. + srcs: ["src/android/test/app/SystemAppTest.java"], +} + +android_test_helper_app { + name: "loadlibrarytest_product_app", + defaults: ["loadlibrarytest_app_defaults"], product_specific: true, - shared_libs: [ - "libbase", + manifest: "loadlibrarytest_product_app_manifest.xml", + srcs: ["src/android/test/app/ProductAppTest.java"], +} + +android_test_helper_app { + name: "loadlibrarytest_vendor_app", + defaults: ["loadlibrarytest_app_defaults"], + vendor: true, + manifest: "loadlibrarytest_vendor_app_manifest.xml", + srcs: ["src/android/test/app/VendorAppTest.java"], +} + +// A normal app installed in /data. +android_test_helper_app { + name: "loadlibrarytest_data_app", + defaults: ["loadlibrarytest_app_defaults"], + manifest: "loadlibrarytest_data_app_manifest.xml", + srcs: ["src/android/test/app/DataAppTest.java"], +} + +java_test_host { + name: "libnativeloader_e2e_tests", + defaults: ["art_module_source_build_java_defaults"], + srcs: ["src/android/test/hostside/*.java"], + libs: [ + "compatibility-tradefed", + "tradefed", + ], + data: [ + ":library_container_app", + ":libnativeloader_system_shared_lib", + ":libnativeloader_system_ext_shared_lib", + ":libnativeloader_product_shared_lib", + ":libnativeloader_vendor_shared_lib", + ":loadlibrarytest_system_priv_app", + ":loadlibrarytest_system_app", + ":loadlibrarytest_system_ext_app", + ":loadlibrarytest_product_app", + ":loadlibrarytest_vendor_app", + ":loadlibrarytest_data_app", ], + test_config: "libnativeloader_e2e_tests.xml", + test_suites: ["general-tests"], } diff --git a/libnativeloader/test/Android.mk b/libnativeloader/test/Android.mk deleted file mode 100644 index 95fa68af68..0000000000 --- a/libnativeloader/test/Android.mk +++ /dev/null @@ -1,72 +0,0 @@ -# -# Copyright (C) 2017 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. -# -LOCAL_PATH:= $(call my-dir) - -include $(CLEAR_VARS) -LOCAL_MODULE := public.libraries-oem1.txt -LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0 -LOCAL_LICENSE_CONDITIONS := notice -LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../NOTICE -LOCAL_SRC_FILES:= $(LOCAL_MODULE) -LOCAL_MODULE_CLASS := ETC -LOCAL_MODULE_PATH := $(TARGET_OUT_ETC) -include $(BUILD_PREBUILT) - -include $(CLEAR_VARS) -LOCAL_MODULE := public.libraries-oem2.txt -LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0 -LOCAL_LICENSE_CONDITIONS := notice -LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../NOTICE -LOCAL_SRC_FILES:= $(LOCAL_MODULE) -LOCAL_MODULE_CLASS := ETC -LOCAL_MODULE_PATH := $(TARGET_OUT_ETC) -include $(BUILD_PREBUILT) - -include $(CLEAR_VARS) -LOCAL_MODULE := public.libraries-product1.txt -LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0 -LOCAL_LICENSE_CONDITIONS := notice -LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../NOTICE -LOCAL_SRC_FILES:= $(LOCAL_MODULE) -LOCAL_MODULE_CLASS := ETC -LOCAL_MODULE_PATH := $(TARGET_OUT_PRODUCT_ETC) -include $(BUILD_PREBUILT) - -include $(CLEAR_VARS) -LOCAL_PACKAGE_NAME := oemlibrarytest-system -LOCAL_MODULE_TAGS := tests -LOCAL_MANIFEST_FILE := system/AndroidManifest.xml -LOCAL_SRC_FILES := $(call all-java-files-under, src) -LOCAL_SDK_VERSION := current -LOCAL_PROGUARD_ENABLED := disabled -LOCAL_MODULE_PATH := $(TARGET_OUT_APPS) -LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0 -LOCAL_LICENSE_CONDITIONS := notice -LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../NOTICE -include $(BUILD_PACKAGE) - -include $(CLEAR_VARS) -LOCAL_PACKAGE_NAME := oemlibrarytest-vendor -LOCAL_MODULE_TAGS := tests -LOCAL_MANIFEST_FILE := vendor/AndroidManifest.xml -LOCAL_SRC_FILES := $(call all-java-files-under, src) -LOCAL_SDK_VERSION := current -LOCAL_PROGUARD_ENABLED := disabled -LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR_APPS) -LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0 -LOCAL_LICENSE_CONDITIONS := notice -LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../NOTICE -include $(BUILD_PACKAGE) diff --git a/libnativeloader/test/libnativeloader_e2e_tests.xml b/libnativeloader/test/libnativeloader_e2e_tests.xml new file mode 100644 index 0000000000..d4f6348886 --- /dev/null +++ b/libnativeloader/test/libnativeloader_e2e_tests.xml @@ -0,0 +1,47 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2021 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. +--> +<configuration description="Config for libnativeloader e2e test cases"> + <option name="test-suite-tag" value="libnativeloader_e2e_tests" /> + <option name="test-suite-tag" value="apct" /> + <option name="config-descriptor:metadata" key="mainline-param" value="com.google.android.art.apex" /> + + <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" /> + + <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"> + <!-- We push all files in LibnativeloaderTest.java, but use this + preparer to make partitions writable. That since remounting may + require a device reboot, and then it's important that the + `setenforce 0` from DisableSELinuxTargetPreparer occurs after that. --> + <option name="remount-system" value="true" /> + <option name="remount-vendor" value="true" /> + </target_preparer> + + <!-- Vendor native libraries aren't accessible by any apps by sepolicy + rules. For that they need to be labelled same_process_hal_file in a + vendor specific file_contexts file (see + https://source.android.com/docs/core/permissions/namespaces_libraries#adding-additional-native-libraries). + To avoid setting that up to test loading libvendor_private*.so, disable + sepolicy checks while running the tests. It's libnativeloader logic we + want to test here. --> + <target_preparer class="com.android.tradefed.targetprep.DisableSELinuxTargetPreparer"/> + + <test class="com.android.tradefed.testtype.HostTest" > + <option name="jar" value="libnativeloader_e2e_tests.jar" /> + </test> + + <!-- Only run tests if the device under test is SDK version 31 (Android 12) or above. --> + <object type="module_controller" class="com.android.tradefed.testtype.suite.module.Sdk31ModuleController" /> +</configuration> diff --git a/libnativeloader/test/system/AndroidManifest.xml b/libnativeloader/test/library_container_app_manifest.xml index c3048891a8..20030de7eb 100644 --- a/libnativeloader/test/system/AndroidManifest.xml +++ b/libnativeloader/test/library_container_app_manifest.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <!-- - * Copyright (C) 2018 The Android Open Source Project + * Copyright (C) 2022 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. @@ -16,16 +16,5 @@ --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="android.test.app.system"> - - <application> - <activity android:name="android.test.app.TestActivity" > - <intent-filter> - <action android:name="android.intent.action.MAIN" /> - <category android:name="android.intent.category.LAUNCHER" /> - </intent-filter> - </activity> - </application> - + package="android.test.app.container"> </manifest> - diff --git a/libnativeloader/test/libsystem_testlib.cc b/libnativeloader/test/libsystem_testlib.cc new file mode 100644 index 0000000000..97d32237b4 --- /dev/null +++ b/libnativeloader/test/libsystem_testlib.cc @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2022 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 <dlfcn.h> + +#include "log/log.h" + +static void __attribute__((constructor)) ctor() { + // Load a library that should be available to system libraries through a + // linked namespace (i.e. is not directly in /system/${LIB}), and that is not + // in public.libraries.txt. We use a real one to avoid having to set up an + // APEX test fixture and rerun linkerconfig. + void* h = dlopen("libandroidicu.so", RTLD_NOW); + if (h == nullptr) { + LOG_ALWAYS_FATAL("Failed to load dependency: %s", dlerror()); + } + dlclose(h); +} diff --git a/libnativeloader/test/loadlibrarytest_data_app_manifest.xml b/libnativeloader/test/loadlibrarytest_data_app_manifest.xml new file mode 100644 index 0000000000..4be78f84f9 --- /dev/null +++ b/libnativeloader/test/loadlibrarytest_data_app_manifest.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + * Copyright (C) 2022 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. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="android.test.app.data"> + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="android.test.app.data" /> + <application> + <uses-library android:required="false" android:name="android.test.systemsharedlib" /> + <uses-library android:required="false" android:name="android.test.systemextsharedlib" /> + <uses-library android:required="false" android:name="android.test.productsharedlib" /> + <uses-library android:required="false" android:name="android.test.vendorsharedlib" /> + <uses-native-library android:required="false" android:name="libsystem_extpub.oem1.so" /> + <uses-native-library android:required="false" android:name="libsystem_extpub.oem2.so" /> + <uses-native-library android:required="false" android:name="libsystem_extpub1.oem1.so" /> + <uses-native-library android:required="false" android:name="libsystem_extpub2.oem1.so" /> + <uses-native-library android:required="false" android:name="libsystem_extpub3.oem1.so" /> + <uses-native-library android:required="false" android:name="libproduct_extpub.product1.so" /> + <uses-native-library android:required="false" android:name="libproduct_extpub1.product1.so" /> + <uses-native-library android:required="false" android:name="libproduct_extpub2.product1.so" /> + <uses-native-library android:required="false" android:name="libproduct_extpub3.product1.so" /> + </application> +</manifest> + diff --git a/libnativeloader/test/loadlibrarytest_product_app_manifest.xml b/libnativeloader/test/loadlibrarytest_product_app_manifest.xml new file mode 100644 index 0000000000..9061c396e1 --- /dev/null +++ b/libnativeloader/test/loadlibrarytest_product_app_manifest.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + * Copyright (C) 2018 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. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="android.test.app.product"> + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="android.test.app.product" /> + <application> + <uses-library android:required="false" android:name="android.test.systemsharedlib" /> + <uses-library android:required="false" android:name="android.test.systemextsharedlib" /> + <uses-library android:required="false" android:name="android.test.productsharedlib" /> + <uses-library android:required="false" android:name="android.test.vendorsharedlib" /> + <uses-native-library android:required="false" android:name="libsystem_extpub.oem1.so" /> + <uses-native-library android:required="false" android:name="libsystem_extpub.oem2.so" /> + <uses-native-library android:required="false" android:name="libsystem_extpub1.oem1.so" /> + <uses-native-library android:required="false" android:name="libsystem_extpub2.oem1.so" /> + <uses-native-library android:required="false" android:name="libsystem_extpub3.oem1.so" /> + <uses-native-library android:required="false" android:name="libproduct_extpub.product1.so" /> + <uses-native-library android:required="false" android:name="libproduct_extpub1.product1.so" /> + <uses-native-library android:required="false" android:name="libproduct_extpub2.product1.so" /> + <uses-native-library android:required="false" android:name="libproduct_extpub3.product1.so" /> + </application> +</manifest> + diff --git a/libnativeloader/test/loadlibrarytest_system_app_manifest.xml b/libnativeloader/test/loadlibrarytest_system_app_manifest.xml new file mode 100644 index 0000000000..7ee7532d1c --- /dev/null +++ b/libnativeloader/test/loadlibrarytest_system_app_manifest.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + * Copyright (C) 2018 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. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="android.test.app.system"> + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="android.test.app.system" /> + <application> + <uses-library android:required="false" android:name="android.test.systemsharedlib" /> + <uses-library android:required="false" android:name="android.test.systemextsharedlib" /> + <uses-library android:required="false" android:name="android.test.productsharedlib" /> + <uses-library android:required="false" android:name="android.test.vendorsharedlib" /> + <!-- System apps get a shared classloader namespace, so they don't need + uses-native-library entries for anything in /system or /system_ext. --> + <uses-native-library android:required="false" android:name="libproduct_extpub.product1.so" /> + <uses-native-library android:required="false" android:name="libproduct_extpub1.product1.so" /> + <uses-native-library android:required="false" android:name="libproduct_extpub2.product1.so" /> + <uses-native-library android:required="false" android:name="libproduct_extpub3.product1.so" /> + </application> +</manifest> + diff --git a/libnativeloader/test/loadlibrarytest_system_ext_app_manifest.xml b/libnativeloader/test/loadlibrarytest_system_ext_app_manifest.xml new file mode 100644 index 0000000000..a2c1a2c8db --- /dev/null +++ b/libnativeloader/test/loadlibrarytest_system_ext_app_manifest.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + * Copyright (C) 2018 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. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="android.test.app.system_ext"> + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="android.test.app.system_ext" /> + <application> + <uses-library android:required="false" android:name="android.test.systemsharedlib" /> + <uses-library android:required="false" android:name="android.test.systemextsharedlib" /> + <uses-library android:required="false" android:name="android.test.productsharedlib" /> + <uses-library android:required="false" android:name="android.test.vendorsharedlib" /> + <!-- System apps get a shared classloader namespace, so they don't need + uses-native-library entries for anything in /system or /system_ext. --> + <uses-native-library android:required="false" android:name="libproduct_extpub.product1.so" /> + <uses-native-library android:required="false" android:name="libproduct_extpub1.product1.so" /> + <uses-native-library android:required="false" android:name="libproduct_extpub2.product1.so" /> + <uses-native-library android:required="false" android:name="libproduct_extpub3.product1.so" /> + </application> +</manifest> + diff --git a/libnativeloader/test/loadlibrarytest_system_priv_app_manifest.xml b/libnativeloader/test/loadlibrarytest_system_priv_app_manifest.xml new file mode 100644 index 0000000000..87a30cec12 --- /dev/null +++ b/libnativeloader/test/loadlibrarytest_system_priv_app_manifest.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + * Copyright (C) 2018 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. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="android.test.app.system_priv"> + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="android.test.app.system_priv" /> + <application> + <uses-library android:required="false" android:name="android.test.systemsharedlib" /> + <uses-library android:required="false" android:name="android.test.systemextsharedlib" /> + <uses-library android:required="false" android:name="android.test.productsharedlib" /> + <uses-library android:required="false" android:name="android.test.vendorsharedlib" /> + <!-- System apps get a shared classloader namespace, so they don't need + uses-native-library entries for anything in /system or /system_ext. --> + <uses-native-library android:required="false" android:name="libproduct_extpub.product1.so" /> + <uses-native-library android:required="false" android:name="libproduct_extpub1.product1.so" /> + <uses-native-library android:required="false" android:name="libproduct_extpub2.product1.so" /> + <uses-native-library android:required="false" android:name="libproduct_extpub3.product1.so" /> + </application> +</manifest> + diff --git a/libnativeloader/test/loadlibrarytest_vendor_app_manifest.xml b/libnativeloader/test/loadlibrarytest_vendor_app_manifest.xml new file mode 100644 index 0000000000..b3434fb930 --- /dev/null +++ b/libnativeloader/test/loadlibrarytest_vendor_app_manifest.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + * Copyright (C) 2018 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. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="android.test.app.vendor"> + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="android.test.app.vendor" /> + <application> + <uses-library android:required="false" android:name="android.test.systemsharedlib" /> + <uses-library android:required="false" android:name="android.test.systemextsharedlib" /> + <uses-library android:required="false" android:name="android.test.productsharedlib" /> + <uses-library android:required="false" android:name="android.test.vendorsharedlib" /> + <uses-native-library android:required="false" android:name="libsystem_extpub.oem1.so" /> + <uses-native-library android:required="false" android:name="libsystem_extpub.oem2.so" /> + <uses-native-library android:required="false" android:name="libsystem_extpub1.oem1.so" /> + <uses-native-library android:required="false" android:name="libsystem_extpub2.oem1.so" /> + <uses-native-library android:required="false" android:name="libsystem_extpub3.oem1.so" /> + <uses-native-library android:required="false" android:name="libproduct_extpub.product1.so" /> + <uses-native-library android:required="false" android:name="libproduct_extpub1.product1.so" /> + <uses-native-library android:required="false" android:name="libproduct_extpub2.product1.so" /> + <uses-native-library android:required="false" android:name="libproduct_extpub3.product1.so" /> + </application> +</manifest> + diff --git a/libnativeloader/test/public.libraries-oem1.txt b/libnativeloader/test/public.libraries-oem1.txt deleted file mode 100644 index f9433e2a04..0000000000 --- a/libnativeloader/test/public.libraries-oem1.txt +++ /dev/null @@ -1,2 +0,0 @@ -libfoo.oem1.so -libbar.oem1.so diff --git a/libnativeloader/test/public.libraries-oem2.txt b/libnativeloader/test/public.libraries-oem2.txt deleted file mode 100644 index de6bdb08e0..0000000000 --- a/libnativeloader/test/public.libraries-oem2.txt +++ /dev/null @@ -1,2 +0,0 @@ -libfoo.oem2.so -libbar.oem2.so diff --git a/libnativeloader/test/public.libraries-product1.txt b/libnativeloader/test/public.libraries-product1.txt deleted file mode 100644 index 358154c626..0000000000 --- a/libnativeloader/test/public.libraries-product1.txt +++ /dev/null @@ -1,2 +0,0 @@ -libfoo.product1.so -libbar.product1.so diff --git a/libnativeloader/test/runtest.sh b/libnativeloader/test/runtest.sh deleted file mode 100755 index 40beb5b4d5..0000000000 --- a/libnativeloader/test/runtest.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash -adb root -adb remount -adb sync -adb shell stop -adb shell start -sleep 5 # wait until device reboots -adb logcat -c; -adb shell am start -n android.test.app.system/android.test.app.TestActivity -adb shell am start -n android.test.app.vendor/android.test.app.TestActivity -adb logcat | grep android.test.app diff --git a/libnativeloader/test/src/android/test/app/DataAppTest.java b/libnativeloader/test/src/android/test/app/DataAppTest.java new file mode 100644 index 0000000000..9403494df6 --- /dev/null +++ b/libnativeloader/test/src/android/test/app/DataAppTest.java @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2022 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. + */ + +package android.test.app; + +import android.test.lib.TestUtils; +import android.test.productsharedlib.ProductSharedLib; +import android.test.systemextsharedlib.SystemExtSharedLib; +import android.test.systemsharedlib.SystemSharedLib; +import android.test.vendorsharedlib.VendorSharedLib; +import androidx.test.filters.MediumTest; +import androidx.test.runner.AndroidJUnit4; +import org.junit.Test; +import org.junit.runner.RunWith; + +@MediumTest +@RunWith(AndroidJUnit4.class) +public class DataAppTest { + @Test + public void testLoadExtendedPublicLibraries() { + System.loadLibrary("system_extpub.oem1"); + System.loadLibrary("system_extpub.oem2"); + System.loadLibrary("system_extpub1.oem1"); + TestUtils.assertLinkerNamespaceError( // Missing <uses-native-library>. + () -> System.loadLibrary("system_extpub_nouses.oem2")); + System.loadLibrary("product_extpub.product1"); + System.loadLibrary("product_extpub1.product1"); + } + + @Test + public void testLoadPrivateLibraries() { + TestUtils.assertLinkerNamespaceError(() -> System.loadLibrary("system_private1")); + TestUtils.assertLinkerNamespaceError(() -> System.loadLibrary("systemext_private1")); + TestUtils.assertLibraryNotFound(() -> System.loadLibrary("product_private1")); + TestUtils.assertLibraryNotFound(() -> System.loadLibrary("vendor_private1")); + } + + @Test + public void testLoadExtendedPublicLibrariesViaSystemSharedLib() { + SystemSharedLib.loadLibrary("system_extpub2.oem1"); + SystemSharedLib.loadLibrary("product_extpub2.product1"); + } + + @Test + public void testLoadPrivateLibrariesViaSystemSharedLib() { + // TODO(b/237577392): Loading a private native system library via a shared system library + // ought to work. + // SystemSharedLib.loadLibrary("system_private2"); + // SystemSharedLib.loadLibrary("systemext_private2"); + TestUtils.assertLibraryNotFound(() -> SystemSharedLib.loadLibrary("product_private2")); + TestUtils.assertLibraryNotFound(() -> SystemSharedLib.loadLibrary("vendor_private2")); + } + + @Test + public void testLoadPrivateLibrariesViaSystemExtSharedLib() { + // TODO(b/237577392): Loading a private native system library via a shared system library + // ought to work. + // SystemExtSharedLib.loadLibrary("system_private3"); + // SystemExtSharedLib.loadLibrary("systemext_private3"); + TestUtils.assertLibraryNotFound(() -> SystemExtSharedLib.loadLibrary("product_private3")); + TestUtils.assertLibraryNotFound(() -> SystemExtSharedLib.loadLibrary("vendor_private3")); + } + + @Test + public void testLoadPrivateLibrariesViaProductSharedLib() { + TestUtils.assertLinkerNamespaceError(() -> ProductSharedLib.loadLibrary("system_private4")); + TestUtils.assertLinkerNamespaceError( + () -> ProductSharedLib.loadLibrary("systemext_private4")); + ProductSharedLib.loadLibrary("product_private4"); + TestUtils.assertLibraryNotFound(() -> ProductSharedLib.loadLibrary("vendor_private4")); + } + + @Test + public void testLoadPrivateLibrariesViaVendorSharedLib() { + TestUtils.assertLinkerNamespaceError(() -> VendorSharedLib.loadLibrary("system_private5")); + TestUtils.assertLinkerNamespaceError( + () -> VendorSharedLib.loadLibrary("systemext_private5")); + TestUtils.assertLibraryNotFound(() -> VendorSharedLib.loadLibrary("product_private5")); + VendorSharedLib.loadLibrary("vendor_private5"); + } + + @Test + public void testLoadExtendedPublicLibrariesWithAbsolutePaths() { + System.load(TestUtils.libPath("/system", "system_extpub3.oem1")); + System.load(TestUtils.libPath("/product", "product_extpub3.product1")); + } + + @Test + public void testLoadPrivateLibrariesWithAbsolutePaths() { + TestUtils.assertLinkerNamespaceError( + () -> System.load(TestUtils.libPath("/system", "system_private6"))); + TestUtils.assertLinkerNamespaceError( + () -> System.load(TestUtils.libPath("/system_ext", "systemext_private6"))); + TestUtils.assertLinkerNamespaceError( + () -> System.load(TestUtils.libPath("/product", "product_private6"))); + TestUtils.assertLinkerNamespaceError( + () -> System.load(TestUtils.libPath("/vendor", "vendor_private6"))); + } +} diff --git a/libnativeloader/test/src/android/test/app/ProductAppTest.java b/libnativeloader/test/src/android/test/app/ProductAppTest.java new file mode 100644 index 0000000000..7ec817b642 --- /dev/null +++ b/libnativeloader/test/src/android/test/app/ProductAppTest.java @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2022 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. + */ + +package android.test.app; + +import android.test.lib.TestUtils; +import android.test.productsharedlib.ProductSharedLib; +import android.test.systemextsharedlib.SystemExtSharedLib; +import android.test.systemsharedlib.SystemSharedLib; +import android.test.vendorsharedlib.VendorSharedLib; +import androidx.test.filters.MediumTest; +import androidx.test.runner.AndroidJUnit4; +import org.junit.Test; +import org.junit.runner.RunWith; + +@MediumTest +@RunWith(AndroidJUnit4.class) +public class ProductAppTest { + @Test + public void testLoadExtendedPublicLibraries() { + System.loadLibrary("system_extpub.oem1"); + System.loadLibrary("system_extpub.oem2"); + System.loadLibrary("system_extpub1.oem1"); + TestUtils.assertLinkerNamespaceError( // Missing <uses-native-library>. + () -> System.loadLibrary("system_extpub_nouses.oem2")); + System.loadLibrary("product_extpub.product1"); + System.loadLibrary("product_extpub1.product1"); + } + + @Test + public void testLoadPrivateLibraries() { + TestUtils.assertLinkerNamespaceError(() -> System.loadLibrary("system_private1")); + TestUtils.assertLinkerNamespaceError(() -> System.loadLibrary("systemext_private1")); + System.loadLibrary("product_private1"); + TestUtils.assertLibraryNotFound(() -> System.loadLibrary("vendor_private1")); + } + + @Test + public void testLoadExtendedPublicLibrariesViaSystemSharedLib() { + SystemSharedLib.loadLibrary("system_extpub2.oem1"); + SystemSharedLib.loadLibrary("product_extpub2.product1"); + } + + @Test + public void testLoadPrivateLibrariesViaSystemSharedLib() { + // TODO(b/237577392): Loading a private native system library via a shared system library + // ought to work. + // SystemSharedLib.loadLibrary("system_private2"); + // SystemSharedLib.loadLibrary("systemext_private2"); + TestUtils.assertLibraryNotFound(() -> SystemSharedLib.loadLibrary("product_private2")); + TestUtils.assertLibraryNotFound(() -> SystemSharedLib.loadLibrary("vendor_private2")); + } + + @Test + public void testLoadPrivateLibrariesViaSystemExtSharedLib() { + // TODO(b/237577392): Loading a private native system library via a shared system library + // ought to work. + // SystemExtSharedLib.loadLibrary("system_private3"); + // SystemExtSharedLib.loadLibrary("systemext_private3"); + TestUtils.assertLibraryNotFound(() -> SystemExtSharedLib.loadLibrary("product_private3")); + TestUtils.assertLibraryNotFound(() -> SystemExtSharedLib.loadLibrary("vendor_private3")); + } + + @Test + public void testLoadPrivateLibrariesViaProductSharedLib() { + TestUtils.assertLinkerNamespaceError(() -> ProductSharedLib.loadLibrary("system_private4")); + TestUtils.assertLinkerNamespaceError( + () -> ProductSharedLib.loadLibrary("systemext_private4")); + ProductSharedLib.loadLibrary("product_private4"); + TestUtils.assertLibraryNotFound(() -> ProductSharedLib.loadLibrary("vendor_private4")); + } + + @Test + public void testLoadPrivateLibrariesViaVendorSharedLib() { + TestUtils.assertLinkerNamespaceError(() -> VendorSharedLib.loadLibrary("system_private5")); + TestUtils.assertLinkerNamespaceError( + () -> VendorSharedLib.loadLibrary("systemext_private5")); + TestUtils.assertLibraryNotFound(() -> VendorSharedLib.loadLibrary("product_private5")); + VendorSharedLib.loadLibrary("vendor_private5"); + } + + @Test + public void testLoadExtendedPublicLibrariesWithAbsolutePaths() { + System.load(TestUtils.libPath("/system", "system_extpub3.oem1")); + System.load(TestUtils.libPath("/product", "product_extpub3.product1")); + } + + @Test + public void testLoadPrivateLibrariesWithAbsolutePaths() { + TestUtils.assertLinkerNamespaceError( + () -> System.load(TestUtils.libPath("/system", "system_private6"))); + TestUtils.assertLinkerNamespaceError( + () -> System.load(TestUtils.libPath("/system_ext", "systemext_private6"))); + System.load(TestUtils.libPath("/product", "product_private6")); + TestUtils.assertLinkerNamespaceError( + () -> System.load(TestUtils.libPath("/vendor", "vendor_private6"))); + } +} diff --git a/libnativeloader/test/src/android/test/app/SystemAppTest.java b/libnativeloader/test/src/android/test/app/SystemAppTest.java new file mode 100644 index 0000000000..cabdfb7e75 --- /dev/null +++ b/libnativeloader/test/src/android/test/app/SystemAppTest.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2022 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. + */ + +package android.test.app; + +import android.test.lib.TestUtils; +import android.test.productsharedlib.ProductSharedLib; +import android.test.systemextsharedlib.SystemExtSharedLib; +import android.test.systemsharedlib.SystemSharedLib; +import android.test.vendorsharedlib.VendorSharedLib; +import androidx.test.filters.MediumTest; +import androidx.test.runner.AndroidJUnit4; +import org.junit.Test; +import org.junit.runner.RunWith; + +// These tests are run from /system/app, /system/priv-app, and /system_ext/app. +@MediumTest +@RunWith(AndroidJUnit4.class) +public class SystemAppTest { + @Test + public void testLoadExtendedPublicLibraries() { + System.loadLibrary("system_extpub.oem1"); + System.loadLibrary("system_extpub.oem2"); + System.loadLibrary("system_extpub1.oem1"); + // Missing <uses-native-library> not relevant for system apps, which have shared classloader + // namespaces. + System.loadLibrary("system_extpub_nouses.oem2"); + System.loadLibrary("product_extpub.product1"); + System.loadLibrary("product_extpub1.product1"); + } + + @Test + public void testLoadPrivateLibraries() { + System.loadLibrary("system_private1"); + System.loadLibrary("systemext_private1"); + TestUtils.assertLibraryNotFound(() -> System.loadLibrary("product_private1")); + TestUtils.assertLibraryNotFound(() -> System.loadLibrary("vendor_private1")); + } + + @Test + public void testLoadExtendedPublicLibrariesViaSystemSharedLib() { + SystemSharedLib.loadLibrary("system_extpub2.oem1"); + SystemSharedLib.loadLibrary("product_extpub2.product1"); + } + + @Test + public void testLoadPrivateLibrariesViaSystemSharedLib() { + SystemSharedLib.loadLibrary("system_private2"); + SystemSharedLib.loadLibrary("systemext_private2"); + TestUtils.assertLibraryNotFound(() -> SystemSharedLib.loadLibrary("product_private2")); + TestUtils.assertLibraryNotFound(() -> SystemSharedLib.loadLibrary("vendor_private2")); + } + + @Test + public void testLoadPrivateLibrariesViaSystemExtSharedLib() { + SystemExtSharedLib.loadLibrary("system_private3"); + SystemExtSharedLib.loadLibrary("systemext_private3"); + TestUtils.assertLibraryNotFound(() -> SystemExtSharedLib.loadLibrary("product_private3")); + TestUtils.assertLibraryNotFound(() -> SystemExtSharedLib.loadLibrary("vendor_private3")); + } + + @Test + public void testLoadPrivateLibrariesViaProductSharedLib() { + ProductSharedLib.loadLibrary("system_private4"); + ProductSharedLib.loadLibrary("systemext_private4"); + TestUtils.assertLibraryNotFound(() -> ProductSharedLib.loadLibrary("product_private4")); + TestUtils.assertLibraryNotFound(() -> ProductSharedLib.loadLibrary("vendor_private4")); + } + + @Test + public void testLoadPrivateLibrariesViaVendorSharedLib() { + VendorSharedLib.loadLibrary("system_private5"); + VendorSharedLib.loadLibrary("systemext_private5"); + TestUtils.assertLibraryNotFound(() -> VendorSharedLib.loadLibrary("product_private5")); + TestUtils.assertLibraryNotFound(() -> VendorSharedLib.loadLibrary("vendor_private5")); + } + + @Test + public void testLoadExtendedPublicLibrariesWithAbsolutePaths() { + System.load(TestUtils.libPath("/system", "system_extpub3.oem1")); + System.load(TestUtils.libPath("/product", "product_extpub3.product1")); + } + + @Test + public void testLoadPrivateLibrariesWithAbsolutePaths() { + System.load(TestUtils.libPath("/system", "system_private6")); + System.load(TestUtils.libPath("/system_ext", "systemext_private6")); + TestUtils.assertLinkerNamespaceError( + () -> System.load(TestUtils.libPath("/product", "product_private6"))); + TestUtils.assertLinkerNamespaceError( + () -> System.load(TestUtils.libPath("/vendor", "vendor_private6"))); + } +} diff --git a/libnativeloader/test/src/android/test/app/TestActivity.java b/libnativeloader/test/src/android/test/app/TestActivity.java deleted file mode 100644 index a7a455d33d..0000000000 --- a/libnativeloader/test/src/android/test/app/TestActivity.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2018 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. - */ - -package android.test.app; - -import android.app.Activity; -import android.os.Bundle; -import android.util.Log; - -public class TestActivity extends Activity { - - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - tryLoadingLib("foo.oem1"); - tryLoadingLib("bar.oem1"); - tryLoadingLib("foo.oem2"); - tryLoadingLib("bar.oem2"); - tryLoadingLib("foo.product1"); - tryLoadingLib("bar.product1"); - } - - private void tryLoadingLib(String name) { - try { - System.loadLibrary(name); - Log.d(getPackageName(), "library " + name + " is successfully loaded"); - } catch (UnsatisfiedLinkError e) { - Log.d(getPackageName(), "failed to load libarary " + name, e); - } - } -} diff --git a/libnativeloader/test/src/android/test/app/VendorAppTest.java b/libnativeloader/test/src/android/test/app/VendorAppTest.java new file mode 100644 index 0000000000..10d0ea04ee --- /dev/null +++ b/libnativeloader/test/src/android/test/app/VendorAppTest.java @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2022 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. + */ + +package android.test.app; + +import android.test.lib.TestUtils; +import android.test.productsharedlib.ProductSharedLib; +import android.test.systemextsharedlib.SystemExtSharedLib; +import android.test.systemsharedlib.SystemSharedLib; +import android.test.vendorsharedlib.VendorSharedLib; +import androidx.test.filters.MediumTest; +import androidx.test.runner.AndroidJUnit4; +import org.junit.Test; +import org.junit.runner.RunWith; + +@MediumTest +@RunWith(AndroidJUnit4.class) +public class VendorAppTest { + @Test + public void testLoadExtendedPublicLibraries() { + TestUtils.assertLinkerNamespaceError(() -> System.loadLibrary("system_extpub.oem1")); + TestUtils.assertLinkerNamespaceError(() -> System.loadLibrary("system_extpub.oem2")); + TestUtils.assertLinkerNamespaceError(() -> System.loadLibrary("system_extpub1.oem1")); + TestUtils.assertLinkerNamespaceError(() -> System.loadLibrary("system_extpub_nouses.oem2")); + System.loadLibrary("product_extpub.product1"); + System.loadLibrary("product_extpub1.product1"); + } + + @Test + public void testLoadPrivateLibraries() { + TestUtils.assertLinkerNamespaceError(() -> System.loadLibrary("system_private1")); + TestUtils.assertLinkerNamespaceError(() -> System.loadLibrary("systemext_private1")); + TestUtils.assertLibraryNotFound(() -> System.loadLibrary("product_private1")); + System.loadLibrary("vendor_private1"); + } + + @Test + public void testLoadExtendedPublicLibrariesViaSystemSharedLib() { + SystemSharedLib.loadLibrary("system_extpub2.oem1"); + SystemSharedLib.loadLibrary("product_extpub2.product1"); + } + + @Test + public void testLoadPrivateLibrariesViaSystemSharedLib() { + // TODO(b/237577392): Loading a private native system library via a shared system library + // ought to work. + // SystemSharedLib.loadLibrary("system_private2"); + // SystemSharedLib.loadLibrary("systemext_private2"); + TestUtils.assertLibraryNotFound(() -> SystemSharedLib.loadLibrary("product_private2")); + TestUtils.assertLibraryNotFound(() -> SystemSharedLib.loadLibrary("vendor_private2")); + } + + @Test + public void testLoadPrivateLibrariesViaSystemExtSharedLib() { + // TODO(b/237577392): Loading a private native system library via a shared system library + // ought to work. + // SystemExtSharedLib.loadLibrary("system_private3"); + // SystemExtSharedLib.loadLibrary("systemext_private3"); + TestUtils.assertLibraryNotFound(() -> SystemExtSharedLib.loadLibrary("product_private3")); + TestUtils.assertLibraryNotFound(() -> SystemExtSharedLib.loadLibrary("vendor_private3")); + } + + @Test + public void testLoadPrivateLibrariesViaProductSharedLib() { + TestUtils.assertLinkerNamespaceError(() -> ProductSharedLib.loadLibrary("system_private4")); + TestUtils.assertLinkerNamespaceError( + () -> ProductSharedLib.loadLibrary("systemext_private4")); + ProductSharedLib.loadLibrary("product_private4"); + TestUtils.assertLibraryNotFound(() -> ProductSharedLib.loadLibrary("vendor_private4")); + } + + @Test + public void testLoadPrivateLibrariesViaVendorSharedLib() { + TestUtils.assertLinkerNamespaceError(() -> VendorSharedLib.loadLibrary("system_private5")); + TestUtils.assertLinkerNamespaceError( + () -> VendorSharedLib.loadLibrary("systemext_private5")); + TestUtils.assertLibraryNotFound(() -> VendorSharedLib.loadLibrary("product_private5")); + VendorSharedLib.loadLibrary("vendor_private5"); + } + + @Test + public void testLoadExtendedPublicLibrariesWithAbsolutePaths() { + TestUtils.assertLinkerNamespaceError( + () -> System.load(TestUtils.libPath("/system", "system_extpub3.oem1"))); + System.load(TestUtils.libPath("/product", "product_extpub3.product1")); + } + + @Test + public void testLoadPrivateLibrariesWithAbsolutePaths() { + TestUtils.assertLinkerNamespaceError( + () -> System.load(TestUtils.libPath("/system", "system_private6"))); + TestUtils.assertLinkerNamespaceError( + () -> System.load(TestUtils.libPath("/system_ext", "systemext_private6"))); + TestUtils.assertLinkerNamespaceError( + () -> System.load(TestUtils.libPath("/product", "product_private6"))); + System.load(TestUtils.libPath("/vendor", "vendor_private6")); + } +} diff --git a/libnativeloader/test/src/android/test/hostside/LibnativeloaderTest.java b/libnativeloader/test/src/android/test/hostside/LibnativeloaderTest.java new file mode 100644 index 0000000000..55a6dd27b3 --- /dev/null +++ b/libnativeloader/test/src/android/test/hostside/LibnativeloaderTest.java @@ -0,0 +1,388 @@ +/* + * Copyright (C) 2022 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. + */ + +package android.test.hostside; + +import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; + +import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper; +import com.android.tradefed.build.IBuildInfo; +import com.android.tradefed.device.DeviceNotAvailableException; +import com.android.tradefed.device.ITestDevice; +import com.android.tradefed.invoker.IInvocationContext; +import com.android.tradefed.invoker.TestInformation; +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; +import com.android.tradefed.testtype.IAbi; +import com.android.tradefed.testtype.junit4.AfterClassWithInfo; +import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; +import com.android.tradefed.testtype.junit4.BeforeClassWithInfo; +import com.android.tradefed.testtype.junit4.DeviceTestRunOptions; +import com.android.tradefed.util.CommandResult; + +import com.google.common.io.ByteStreams; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +/** + * Test libnativeloader behavior for apps and libs in various partitions by overlaying them over + * the system partitions. Requires root. + */ +@RunWith(DeviceJUnit4ClassRunner.class) +public class LibnativeloaderTest extends BaseHostJUnit4Test { + private static final String TAG = "LibnativeloaderTest"; + private static final String CLEANUP_PATHS_KEY = TAG + ":CLEANUP_PATHS"; + private static final String LOG_FILE_NAME = "TestActivity.log"; + + @BeforeClassWithInfo + public static void beforeClassWithDevice(TestInformation testInfo) throws Exception { + DeviceContext ctx = new DeviceContext(testInfo); + + // A soft reboot is slow, so do setup for all tests and reboot once. + + File libContainerApk = ctx.mBuildHelper.getTestFile("library_container_app.apk"); + try (ZipFile libApk = new ZipFile(libContainerApk)) { + ctx.pushExtendedPublicSystemOemLibs(libApk); + ctx.pushExtendedPublicProductLibs(libApk); + ctx.pushPrivateLibs(libApk); + } + ctx.pushSharedLib( + "/system", "android.test.systemsharedlib", "libnativeloader_system_shared_lib.jar"); + ctx.pushSharedLib("/system_ext", "android.test.systemextsharedlib", + "libnativeloader_system_ext_shared_lib.jar"); + ctx.pushSharedLib("/product", "android.test.productsharedlib", + "libnativeloader_product_shared_lib.jar"); + ctx.pushSharedLib( + "/vendor", "android.test.vendorsharedlib", "libnativeloader_vendor_shared_lib.jar"); + + // "Install" apps in various partitions through plain adb push followed by a soft reboot. We + // need them in these locations to test library loading restrictions, so for all except + // loadlibrarytest_data_app we cannot use ITestDevice.installPackage for it since it only + // installs in /data. + + // For testSystemPrivApp + ctx.pushApk("loadlibrarytest_system_priv_app", "/system/priv-app"); + + // For testSystemApp + ctx.pushApk("loadlibrarytest_system_app", "/system/app"); + + // For testSystemExtApp + ctx.pushApk("loadlibrarytest_system_ext_app", "/system_ext/app"); + + // For testProductApp + ctx.pushApk("loadlibrarytest_product_app", "/product/app"); + + // For testVendorApp + ctx.pushApk("loadlibrarytest_vendor_app", "/vendor/app"); + + ctx.softReboot(); + + // For testDataApp. Install this the normal way after the system server restart. + ctx.installPackage("loadlibrarytest_data_app"); + + testInfo.properties().put(CLEANUP_PATHS_KEY, ctx.mCleanup.getPathList()); + } + + @AfterClassWithInfo + public static void afterClassWithDevice(TestInformation testInfo) throws Exception { + DeviceContext ctx = new DeviceContext(testInfo); + + // Uninstall loadlibrarytest_data_app. + ctx.mDevice.uninstallPackage("android.test.app.data"); + + String cleanupPathList = testInfo.properties().get(CLEANUP_PATHS_KEY); + CleanupPaths cleanup = new CleanupPaths(ctx.mDevice, cleanupPathList); + cleanup.cleanup(); + } + + @Test + public void testSystemPrivApp() throws Exception { + // There's currently no difference in the tests between /system/priv-app and /system/app, so + // let's reuse the same one. + runTests("android.test.app.system_priv", "android.test.app.SystemAppTest"); + } + + @Test + public void testSystemApp() throws Exception { + runTests("android.test.app.system", "android.test.app.SystemAppTest"); + } + + @Test + public void testSystemExtApp() throws Exception { + // /system_ext should behave the same as /system, so run the same test class there. + runTests("android.test.app.system_ext", "android.test.app.SystemAppTest"); + } + + @Test + public void testProductApp() throws Exception { + runTests("android.test.app.product", "android.test.app.ProductAppTest"); + } + + @Test + public void testVendorApp() throws Exception { + runTests("android.test.app.vendor", "android.test.app.VendorAppTest"); + } + + @Test + public void testDataApp() throws Exception { + runTests("android.test.app.data", "android.test.app.DataAppTest"); + } + + private void runTests(String pkgName, String testClassName) throws Exception { + DeviceContext ctx = new DeviceContext(getTestInformation()); + var options = new DeviceTestRunOptions(pkgName) + .setTestClassName(testClassName) + .addInstrumentationArg("libDirName", ctx.libDirName()); + runDeviceTests(options); + } + + // Utility class that keeps track of a set of paths the need to be deleted after testing. + private static class CleanupPaths { + private ITestDevice mDevice; + private List<String> mCleanupPaths; + + CleanupPaths(ITestDevice device) { + mDevice = device; + mCleanupPaths = new ArrayList<String>(); + } + + CleanupPaths(ITestDevice device, String pathList) { + mDevice = device; + mCleanupPaths = Arrays.asList(pathList.split(":")); + } + + String getPathList() { return String.join(":", mCleanupPaths); } + + // Adds the given path, or its topmost nonexisting parent directory, to the list of paths to + // clean up. + void addPath(String devicePath) throws DeviceNotAvailableException { + File path = new File(devicePath); + while (true) { + File parentPath = path.getParentFile(); + if (parentPath == null || mDevice.doesFileExist(parentPath.toString())) { + break; + } + path = parentPath; + } + String nonExistingPath = path.toString(); + if (!mCleanupPaths.contains(nonExistingPath)) { + mCleanupPaths.add(nonExistingPath); + } + } + + void cleanup() throws DeviceNotAvailableException { + // Clean up in reverse order in case several pushed files were in the same nonexisting + // directory. + for (int i = mCleanupPaths.size() - 1; i >= 0; --i) { + mDevice.deleteFile(mCleanupPaths.get(i)); + } + } + } + + // Class for code that needs an ITestDevice. It may be instantiated both in tests and in + // (Before|After)ClassWithInfo. + private static class DeviceContext implements AutoCloseable { + IInvocationContext mContext; + ITestDevice mDevice; + CompatibilityBuildHelper mBuildHelper; + CleanupPaths mCleanup; + private String mTestArch; + + DeviceContext(TestInformation testInfo) { + mContext = testInfo.getContext(); + mDevice = testInfo.getDevice(); + mBuildHelper = new CompatibilityBuildHelper(testInfo.getBuildInfo()); + mCleanup = new CleanupPaths(mDevice); + } + + public void close() throws DeviceNotAvailableException { mCleanup.cleanup(); } + + // Helper class to both push a library to device and record it in a public.libraries-xxx.txt + // file. + class PublicLibs { + private ZipFile mLibApk; + private List<String> mPublicLibs = new ArrayList<String>(); + + PublicLibs(ZipFile libApk) { + mLibApk = libApk; + } + + void addLib(String libName, String destDir, String destName) throws Exception { + pushNativeTestLib(mLibApk, libName, destDir + "/" + destName); + mPublicLibs.add(destName); + } + + void pushPublicLibrariesFile(String path) throws DeviceNotAvailableException { + pushString(mPublicLibs.stream().collect(Collectors.joining("\n")) + "\n", path); + } + } + + void pushExtendedPublicSystemOemLibs(ZipFile libApk) throws Exception { + var oem1Libs = new PublicLibs(libApk); + // Push libsystem_extpub<n>.oem1.so for each test. Since we cannot unload them, we need + // a fresh never-before-loaded library in each loadLibrary call. + for (int i = 1; i <= 3; ++i) { + oem1Libs.addLib("libsystem_testlib.so", "/system/${LIB}", + "libsystem_extpub" + i + ".oem1.so"); + } + oem1Libs.addLib("libsystem_testlib.so", "/system/${LIB}", "libsystem_extpub.oem1.so"); + oem1Libs.pushPublicLibrariesFile("/system/etc/public.libraries-oem1.txt"); + + var oem2Libs = new PublicLibs(libApk); + oem2Libs.addLib("libsystem_testlib.so", "/system/${LIB}", "libsystem_extpub.oem2.so"); + // libextpub_nouses.oem2.so is a library that the test apps don't have + // <uses-native-library> dependencies for. + oem2Libs.addLib( + "libsystem_testlib.so", "/system/${LIB}", "libsystem_extpub_nouses.oem2.so"); + oem2Libs.pushPublicLibrariesFile("/system/etc/public.libraries-oem2.txt"); + } + + void pushExtendedPublicProductLibs(ZipFile libApk) throws Exception { + var product1Libs = new PublicLibs(libApk); + // Push libproduct_extpub<n>.product1.so for each test. Since we cannot unload them, we + // need a fresh never-before-loaded library in each loadLibrary call. + for (int i = 1; i <= 3; ++i) { + product1Libs.addLib("libproduct_testlib.so", "/product/${LIB}", + "libproduct_extpub" + i + ".product1.so"); + } + product1Libs.addLib( + "libproduct_testlib.so", "/product/${LIB}", "libproduct_extpub.product1.so"); + product1Libs.pushPublicLibrariesFile("/product/etc/public.libraries-product1.txt"); + } + + void pushPrivateLibs(ZipFile libApk) throws Exception { + // Push the libraries once for each test. Since we cannot unload them, we need a fresh + // never-before-loaded library in each loadLibrary call. + for (int i = 1; i <= 6; ++i) { + pushNativeTestLib(libApk, "libsystem_testlib.so", + "/system/${LIB}/libsystem_private" + i + ".so"); + pushNativeTestLib(libApk, "libsystem_testlib.so", + "/system_ext/${LIB}/libsystemext_private" + i + ".so"); + pushNativeTestLib(libApk, "libproduct_testlib.so", + "/product/${LIB}/libproduct_private" + i + ".so"); + pushNativeTestLib(libApk, "libvendor_testlib.so", + "/vendor/${LIB}/libvendor_private" + i + ".so"); + } + } + + void pushSharedLib(String partitionDir, String packageName, String buildJarName) + throws Exception { + String path = partitionDir + "/framework/" + packageName + ".jar"; + pushFile(buildJarName, path); + // This permissions xml file is necessary to make it possible to depend on the shared + // library from the test app, even if it's in the same partition. It makes the library + // public to apps in other partitions as well, which is more than we need, but that + // being the case we test all shared libraries from all apps. + pushString("<permissions>\n" + + "<library name=\"" + packageName + "\" file=\"" + path + "\" />\n" + + "</permissions>\n", + partitionDir + "/etc/permissions/" + packageName + ".xml"); + } + + void softReboot() throws DeviceNotAvailableException { + assertCommandSucceeds("setprop dev.bootcomplete 0"); + assertCommandSucceeds("stop"); + assertCommandSucceeds("start"); + mDevice.waitForDeviceAvailable(); + } + + String getTestArch() throws DeviceNotAvailableException { + if (mTestArch == null) { + IAbi abi = mContext.getConfigurationDescriptor().getAbi(); + mTestArch = abi != null ? abi.getName() + : assertCommandSucceeds("getprop ro.product.cpu.abi"); + } + return mTestArch; + } + + String libDirName() throws DeviceNotAvailableException { + return getTestArch().contains("64") ? "lib64" : "lib"; + } + + // Pushes the given file contents to the device at the given destination path. destPath is + // assumed to have no risk of overlapping with existing files, and is deleted in tearDown(), + // along with any directory levels that had to be created. + void pushString(String fileContents, String destPath) throws DeviceNotAvailableException { + mCleanup.addPath(destPath); + assertThat(mDevice.pushString(fileContents, destPath)).isTrue(); + } + + // Like pushString, but pushes a data file included in the host test. + void pushFile(String fileName, String destPath) throws Exception { + mCleanup.addPath(destPath); + assertThat(mDevice.pushFile(mBuildHelper.getTestFile(fileName), destPath)).isTrue(); + } + + void pushApk(String apkBaseName, String destPath) throws Exception { + pushFile(apkBaseName + ".apk", + destPath + "/" + apkBaseName + "/" + apkBaseName + ".apk"); + } + + // Like pushString, but extracts libnativeloader_testlib.so from the library_container_app + // APK and pushes it to destPath. "${LIB}" is replaced with "lib" or "lib64" as appropriate. + void pushNativeTestLib(ZipFile libApk, String libName, String destPath) throws Exception { + String libApkPath = "lib/" + getTestArch() + "/" + libName; + ZipEntry entry = libApk.getEntry(libApkPath); + assertWithMessage("Failed to find " + libApkPath + " in library_container_app.apk") + .that(entry) + .isNotNull(); + + File libraryTempFile; + try (InputStream inStream = libApk.getInputStream(entry)) { + libraryTempFile = writeStreamToTempFile(libName, inStream); + } + + destPath = destPath.replace("${LIB}", libDirName()); + + mCleanup.addPath(destPath); + assertThat(mDevice.pushFile(libraryTempFile, destPath)).isTrue(); + } + + void installPackage(String apkBaseName) throws Exception { + assertThat(mDevice.installPackage(mBuildHelper.getTestFile(apkBaseName + ".apk"), + false /* reinstall */)) + .isNull(); + } + + String assertCommandSucceeds(String command) throws DeviceNotAvailableException { + CommandResult result = mDevice.executeShellV2Command(command); + assertWithMessage(result.toString()).that(result.getExitCode()).isEqualTo(0); + // Remove trailing \n's. + return result.getStdout().trim(); + } + } + + static private File writeStreamToTempFile(String tempFileBaseName, InputStream inStream) + throws Exception { + File hostTempFile = File.createTempFile(tempFileBaseName, null); + try (FileOutputStream outStream = new FileOutputStream(hostTempFile)) { + ByteStreams.copy(inStream, outStream); + } + return hostTempFile; + } +} diff --git a/libnativeloader/test/src/android/test/lib/TestUtils.java b/libnativeloader/test/src/android/test/lib/TestUtils.java new file mode 100644 index 0000000000..1dd917f89f --- /dev/null +++ b/libnativeloader/test/src/android/test/lib/TestUtils.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2022 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. + */ + +package android.test.lib; + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertThrows; + +import androidx.test.platform.app.InstrumentationRegistry; +import org.junit.function.ThrowingRunnable; + +public final class TestUtils { + public static void assertLibraryNotFound(ThrowingRunnable loadLibrary) { + Throwable t = assertThrows(UnsatisfiedLinkError.class, loadLibrary); + assertThat(t.getMessage()).containsMatch("dlopen failed: library .* not found"); + } + + public static void assertLinkerNamespaceError(ThrowingRunnable loadLibrary) { + Throwable t = assertThrows(UnsatisfiedLinkError.class, loadLibrary); + assertThat(t.getMessage()) + .containsMatch("dlopen failed: .* is not accessible for the namespace"); + } + + public static String libPath(String dir, String libName) { + String libDirName = InstrumentationRegistry.getArguments().getString("libDirName"); + return dir + "/" + libDirName + "/lib" + libName + ".so"; + } +} diff --git a/libnativeloader/test/test.cpp b/libnativeloader/test/src/android/test/productsharedlib/ProductSharedLib.java index b166928f0e..a500d2a976 100644 --- a/libnativeloader/test/test.cpp +++ b/libnativeloader/test/src/android/test/productsharedlib/ProductSharedLib.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * Copyright (C) 2022 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. @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#define LOG_TAG "oemlib" -#include <android-base/logging.h> -static __attribute__((constructor)) void test_lib_init() { - LOG(DEBUG) << LIBNAME << " loaded"; +package android.test.productsharedlib; + +public final class ProductSharedLib { + public static void loadLibrary(String name) { System.loadLibrary(name); } } diff --git a/libnativeloader/test/vendor/AndroidManifest.xml b/libnativeloader/test/src/android/test/systemextsharedlib/SystemExtSharedLib.java index c4c1a9c210..1240e12e55 100644 --- a/libnativeloader/test/vendor/AndroidManifest.xml +++ b/libnativeloader/test/src/android/test/systemextsharedlib/SystemExtSharedLib.java @@ -1,6 +1,5 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - * Copyright (C) 2018 The Android Open Source Project +/* + * Copyright (C) 2022 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. @@ -13,19 +12,10 @@ * 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. - --> + */ -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="android.test.app.vendor"> - - <application> - <activity android:name="android.test.app.TestActivity" > - <intent-filter> - <action android:name="android.intent.action.MAIN" /> - <category android:name="android.intent.category.LAUNCHER" /> - </intent-filter> - </activity> - </application> - -</manifest> +package android.test.systemextsharedlib; +public final class SystemExtSharedLib { + public static void loadLibrary(String name) { System.loadLibrary(name); } +} diff --git a/libnativeloader/test/src/android/test/systemsharedlib/SystemSharedLib.java b/libnativeloader/test/src/android/test/systemsharedlib/SystemSharedLib.java new file mode 100644 index 0000000000..8e2af9f79c --- /dev/null +++ b/libnativeloader/test/src/android/test/systemsharedlib/SystemSharedLib.java @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2022 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. + */ + +package android.test.systemsharedlib; + +public final class SystemSharedLib { + public static void loadLibrary(String name) { System.loadLibrary(name); } +} diff --git a/libnativeloader/test/src/android/test/vendorsharedlib/VendorSharedLib.java b/libnativeloader/test/src/android/test/vendorsharedlib/VendorSharedLib.java new file mode 100644 index 0000000000..8859b63db4 --- /dev/null +++ b/libnativeloader/test/src/android/test/vendorsharedlib/VendorSharedLib.java @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2022 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. + */ + +package android.test.vendorsharedlib; + +public final class VendorSharedLib { + public static void loadLibrary(String name) { System.loadLibrary(name); } +} |