diff options
-rw-r--r-- | libnativeloader/Android.bp | 2 | ||||
-rw-r--r-- | libnativeloader/library_namespaces.cpp | 4 | ||||
-rw-r--r-- | libnativeloader/library_namespaces.h | 1 | ||||
-rw-r--r-- | libnativeloader/library_namespaces_test.cpp | 41 | ||||
-rw-r--r-- | libnativeloader/native_loader.cpp | 78 | ||||
-rw-r--r-- | libnativeloader/test/src/android/test/app/DataAppTest.java | 35 | ||||
-rw-r--r-- | libnativeloader/test/src/android/test/app/ProductAppTest.java | 26 | ||||
-rw-r--r-- | libnativeloader/test/src/android/test/app/VendorAppTest.java | 35 | ||||
-rw-r--r-- | libnativeloader/test/src/android/test/lib/AppTestCommon.java | 18 | ||||
-rw-r--r-- | libnativeloader/test/src/android/test/lib/TestUtils.java | 6 | ||||
-rw-r--r-- | runtime/jni/java_vm_ext.cc | 12 |
11 files changed, 201 insertions, 57 deletions
diff --git a/libnativeloader/Android.bp b/libnativeloader/Android.bp index e9c26c592c..484324e7ca 100644 --- a/libnativeloader/Android.bp +++ b/libnativeloader/Android.bp @@ -34,6 +34,7 @@ art_cc_library { "native_loader.cpp", ], header_libs: [ + "art_libartbase_headers", "libnativehelper_header_only", ], shared_libs: [ @@ -66,6 +67,7 @@ art_cc_library { ], static_libs: [ "libPlatformProperties", + "libmodules-utils-build", ], }, }, diff --git a/libnativeloader/library_namespaces.cpp b/libnativeloader/library_namespaces.cpp index e2b27294f9..bd186c122a 100644 --- a/libnativeloader/library_namespaces.cpp +++ b/libnativeloader/library_namespaces.cpp @@ -85,6 +85,7 @@ constexpr const char* kProductLibPath = "/product/" LIB ":/system/product/" LIB; const std::regex kVendorPathRegex("(/system)?/vendor/.*"); const std::regex kProductPathRegex("(/system)?/product/.*"); +const std::regex kSystemPathRegex("/system(_ext)?/.*"); // MUST be tested last. jobject GetParentClassLoader(JNIEnv* env, jobject class_loader) { jclass class_loader_class = env->FindClass("java/lang/ClassLoader"); @@ -103,6 +104,9 @@ ApiDomain GetApiDomainFromPath(const std::string_view path) { if (is_product_treblelized() && std::regex_match(path.begin(), path.end(), kProductPathRegex)) { return API_DOMAIN_PRODUCT; } + if (std::regex_match(path.begin(), path.end(), kSystemPathRegex)) { + return API_DOMAIN_SYSTEM; + } return API_DOMAIN_DEFAULT; } diff --git a/libnativeloader/library_namespaces.h b/libnativeloader/library_namespaces.h index ae1cd88f20..b932a557e0 100644 --- a/libnativeloader/library_namespaces.h +++ b/libnativeloader/library_namespaces.h @@ -53,6 +53,7 @@ using ApiDomain = enum { API_DOMAIN_DEFAULT = 0, // Locations other than those below, in particular for ordinary apps API_DOMAIN_VENDOR = 1, // Vendor partition API_DOMAIN_PRODUCT = 2, // Product partition + API_DOMAIN_SYSTEM = 3, // System and system_ext partitions }; ApiDomain GetApiDomainFromPath(const std::string_view path); diff --git a/libnativeloader/library_namespaces_test.cpp b/libnativeloader/library_namespaces_test.cpp index 7780418846..8e00e2be62 100644 --- a/libnativeloader/library_namespaces_test.cpp +++ b/libnativeloader/library_namespaces_test.cpp @@ -31,40 +31,45 @@ using ::android::base::testing::HasValue; using ::android::base::testing::WithMessage; using ::testing::StartsWith; -TEST(LibraryNamespacesTest, TestGetApiDomainFromPath) { +static ApiDomain GetProductApiDomain(ApiDomain fallback_domain) { // GetApiDomainFromPath returns API_DOMAIN_PRODUCT only if the device is // trebleized and has an unbundled product partition. - ApiDomain api_domain_product = is_product_treblelized() ? API_DOMAIN_PRODUCT : API_DOMAIN_DEFAULT; + return is_product_treblelized() ? API_DOMAIN_PRODUCT : fallback_domain; +} +TEST(LibraryNamespacesTest, TestGetApiDomainFromPath) { EXPECT_EQ(GetApiDomainFromPath("/data/somewhere"), API_DOMAIN_DEFAULT); - EXPECT_EQ(GetApiDomainFromPath("/system/somewhere"), API_DOMAIN_DEFAULT); - EXPECT_EQ(GetApiDomainFromPath("/product/somewhere"), api_domain_product); + EXPECT_EQ(GetApiDomainFromPath("/system/somewhere"), API_DOMAIN_SYSTEM); + EXPECT_EQ(GetApiDomainFromPath("/system_ext/somewhere"), API_DOMAIN_SYSTEM); + EXPECT_EQ(GetApiDomainFromPath("/systemext/somewhere"), API_DOMAIN_DEFAULT); + EXPECT_EQ(GetApiDomainFromPath("/product/somewhere"), GetProductApiDomain(API_DOMAIN_DEFAULT)); EXPECT_EQ(GetApiDomainFromPath("/vendor/somewhere"), API_DOMAIN_VENDOR); - EXPECT_EQ(GetApiDomainFromPath("/system/product/somewhere"), api_domain_product); + EXPECT_EQ(GetApiDomainFromPath("/system/product/somewhere"), + GetProductApiDomain(API_DOMAIN_SYSTEM)); EXPECT_EQ(GetApiDomainFromPath("/system/vendor/somewhere"), API_DOMAIN_VENDOR); EXPECT_EQ(GetApiDomainFromPath(""), API_DOMAIN_DEFAULT); EXPECT_EQ(GetApiDomainFromPath("/"), API_DOMAIN_DEFAULT); EXPECT_EQ(GetApiDomainFromPath("product/somewhere"), API_DOMAIN_DEFAULT); EXPECT_EQ(GetApiDomainFromPath("/product"), API_DOMAIN_DEFAULT); - EXPECT_EQ(GetApiDomainFromPath("/product/"), api_domain_product); + EXPECT_EQ(GetApiDomainFromPath("/product/"), GetProductApiDomain(API_DOMAIN_DEFAULT)); EXPECT_EQ(GetApiDomainFromPath(":/product/"), API_DOMAIN_DEFAULT); EXPECT_EQ(GetApiDomainFromPath("/data/somewhere:/product/somewhere"), API_DOMAIN_DEFAULT); EXPECT_EQ(GetApiDomainFromPath("/vendor/somewhere:/product/somewhere"), API_DOMAIN_VENDOR); - EXPECT_EQ(GetApiDomainFromPath("/product/somewhere:/vendor/somewhere"), api_domain_product); + EXPECT_EQ(GetApiDomainFromPath("/product/somewhere:/vendor/somewhere"), + GetProductApiDomain(API_DOMAIN_DEFAULT)); } TEST(LibraryNamespacesTest, TestGetApiDomainFromPathList) { - // GetApiDomainFromPath returns API_DOMAIN_PRODUCT only if the device is - // trebleized and has an unbundled product partition. - ApiDomain api_domain_product = is_product_treblelized() ? API_DOMAIN_PRODUCT : API_DOMAIN_DEFAULT; - EXPECT_THAT(GetApiDomainFromPathList("/data/somewhere"), HasValue(API_DOMAIN_DEFAULT)); - EXPECT_THAT(GetApiDomainFromPathList("/system/somewhere"), HasValue(API_DOMAIN_DEFAULT)); - EXPECT_THAT(GetApiDomainFromPathList("/product/somewhere"), HasValue(api_domain_product)); + EXPECT_THAT(GetApiDomainFromPathList("/system/somewhere"), HasValue(API_DOMAIN_SYSTEM)); + EXPECT_THAT(GetApiDomainFromPathList("/system_ext/somewhere"), HasValue(API_DOMAIN_SYSTEM)); + EXPECT_THAT(GetApiDomainFromPathList("/product/somewhere"), + HasValue(GetProductApiDomain(API_DOMAIN_DEFAULT))); EXPECT_THAT(GetApiDomainFromPathList("/vendor/somewhere"), HasValue(API_DOMAIN_VENDOR)); - EXPECT_THAT(GetApiDomainFromPathList("/system/product/somewhere"), HasValue(api_domain_product)); + EXPECT_THAT(GetApiDomainFromPathList("/system/product/somewhere"), + HasValue(GetProductApiDomain(API_DOMAIN_SYSTEM))); EXPECT_THAT(GetApiDomainFromPathList("/system/vendor/somewhere"), HasValue(API_DOMAIN_VENDOR)); EXPECT_THAT(GetApiDomainFromPathList(""), HasValue(API_DOMAIN_DEFAULT)); @@ -73,13 +78,17 @@ TEST(LibraryNamespacesTest, TestGetApiDomainFromPathList) { EXPECT_THAT(GetApiDomainFromPathList("/vendor/somewhere:"), HasValue(API_DOMAIN_VENDOR)); EXPECT_THAT(GetApiDomainFromPathList("/data/somewhere:/product/somewhere"), - HasValue(api_domain_product)); - if (api_domain_product == API_DOMAIN_PRODUCT) { + HasValue(GetProductApiDomain(API_DOMAIN_DEFAULT))); + if (GetProductApiDomain(API_DOMAIN_DEFAULT) == API_DOMAIN_PRODUCT) { EXPECT_THAT(GetApiDomainFromPathList("/vendor/somewhere:/product/somewhere"), HasError(WithMessage(StartsWith("Path list crosses partition boundaries")))); EXPECT_THAT(GetApiDomainFromPathList("/product/somewhere:/vendor/somewhere"), HasError(WithMessage(StartsWith("Path list crosses partition boundaries")))); } + EXPECT_THAT(GetApiDomainFromPathList("/system/somewhere:/vendor/somewhere"), + HasError(WithMessage(StartsWith("Path list crosses partition boundaries")))); + EXPECT_THAT(GetApiDomainFromPathList("/system_ext/somewhere:/vendor/somewhere"), + HasError(WithMessage(StartsWith("Path list crosses partition boundaries")))); } } // namespace diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp index 61925431ef..5b4988ae48 100644 --- a/libnativeloader/native_loader.cpp +++ b/libnativeloader/native_loader.cpp @@ -25,6 +25,7 @@ #include <memory> #include <mutex> #include <optional> +#include <regex> #include <string> #include <vector> @@ -32,11 +33,13 @@ #include "android-base/macros.h" #include "android-base/strings.h" #include "android-base/thread_annotations.h" +#include "base/macros.h" #include "nativebridge/native_bridge.h" #include "nativehelper/scoped_utf_chars.h" #include "public_libraries.h" #ifdef ART_TARGET_ANDROID +#include "android-modules-utils/sdk_level.h" #include "library_namespaces.h" #include "log/log.h" #include "nativeloader/dlext_namespaces.h" @@ -51,6 +54,9 @@ namespace { using ::android::base::Result; using ::android::nativeloader::LibraryNamespaces; +const std::regex kPartitionNativeLibPathRegex( + "/(system(_ext)?|(system/)?(vendor|product))/lib(64)?/.*"); + // NATIVELOADER_DEFAULT_NAMESPACE_LIBS is an environment variable that can be // used to list extra libraries (separated by ":") that libnativeloader will // load from the default namespace. The libraries must be listed without paths, @@ -87,6 +93,23 @@ std::optional<NativeLoaderNamespace> FindApexNamespace(const char* caller_locati return std::nullopt; } +Result<NativeLoaderNamespace> GetNamespaceForApiDomain(nativeloader::ApiDomain api_domain, + bool is_bridged) { + switch (api_domain) { + case nativeloader::API_DOMAIN_VENDOR: + return NativeLoaderNamespace::GetExportedNamespace(nativeloader::kVendorNamespaceName, + is_bridged); + case nativeloader::API_DOMAIN_PRODUCT: + return NativeLoaderNamespace::GetExportedNamespace(nativeloader::kProductNamespaceName, + is_bridged); + case nativeloader::API_DOMAIN_SYSTEM: + return NativeLoaderNamespace::GetSystemNamespace(is_bridged); + default: + LOG_FATAL("Invalid API domain %d", api_domain); + UNREACHABLE(); + } +} + Result<void> CreateNativeloaderDefaultNamespaceLibsLink(NativeLoaderNamespace& ns) REQUIRES(g_namespaces_mutex) { const char* links = getenv("NATIVELOADER_DEFAULT_NAMESPACE_LIBS"); @@ -311,6 +334,61 @@ void* OpenNativeLibrary(JNIEnv* env, return handle; } + // If the caller is in any of the system image partitions and the library is + // in the same partition then load it without regards to public library + // restrictions. This is only done if the library is specified by an absolute + // path, so we don't affect the lookup process for libraries specified by name + // only. + if (caller_location != nullptr && + // Check that the library is in the partition-wide native library + // location. Apps in the partition may have their own native libraries, + // and those should still be loaded with the app's classloader namespace. + std::regex_match(path, kPartitionNativeLibPathRegex) && + // Don't do this if the system image is older than V, to avoid any compat + // issues with apps and shared libs in them. + android::modules::sdklevel::IsAtLeastV()) { + nativeloader::ApiDomain caller_api_domain = nativeloader::GetApiDomainFromPath(caller_location); + if (caller_api_domain != nativeloader::API_DOMAIN_DEFAULT) { + nativeloader::ApiDomain library_api_domain = nativeloader::GetApiDomainFromPath(path); + + if (library_api_domain == caller_api_domain) { + bool is_bridged = false; + if (library_path_j != nullptr) { + ScopedUtfChars library_path_utf_chars(env, library_path_j); + if (library_path_utf_chars[0] != '\0') { + is_bridged = NativeBridgeIsPathSupported(library_path_utf_chars.c_str()); + } + } + + Result<NativeLoaderNamespace> ns = GetNamespaceForApiDomain(caller_api_domain, is_bridged); + if (!ns.ok()) { + ALOGD("Failed to find ns for caller %s in API domain %d to load %s (is_bridged=%b): %s", + caller_location, + caller_api_domain, + path, + is_bridged, + ns.error().message().c_str()); + *error_msg = strdup(ns.error().message().c_str()); + return nullptr; + } + + *needs_native_bridge = ns.value().IsBridged(); + Result<void*> handle = ns.value().Load(path); + ALOGD("Load %s using ns %s for caller %s in same partition (is_bridged=%b): %s", + path, + ns.value().name().c_str(), + caller_location, + is_bridged, + handle.ok() ? "ok" : handle.error().message().c_str()); + if (!handle.ok()) { + *error_msg = strdup(handle.error().message().c_str()); + return nullptr; + } + return handle.value(); + } + } + } + std::lock_guard<std::mutex> guard(g_namespaces_mutex); { diff --git a/libnativeloader/test/src/android/test/app/DataAppTest.java b/libnativeloader/test/src/android/test/app/DataAppTest.java index 905b5bb0d1..44aa9111cd 100644 --- a/libnativeloader/test/src/android/test/app/DataAppTest.java +++ b/libnativeloader/test/src/android/test/app/DataAppTest.java @@ -67,11 +67,18 @@ public class DataAppTest extends AppTestCommon { @Test public void testLoadPrivateLibrariesViaSystemSharedLib() { - // TODO(b/237577392): Loading a private native system library via a shared system library - // ought to work. - TestUtils.assertLibraryInaccessible(() -> SystemSharedLib.loadLibrary("system_private2")); - TestUtils.assertLibraryInaccessible( - () -> SystemSharedLib.loadLibrary("systemext_private2")); + if (TestUtils.canLoadPrivateLibsFromSamePartition()) { + // TODO(b/186729817): These loads work because the findLibrary call in + // loadLibrary0 in Runtime.java searches the system libs and converts + // them to absolute paths. + SystemSharedLib.loadLibrary("system_private2"); + SystemSharedLib.loadLibrary("systemext_private2"); + } else { + TestUtils.assertLibraryInaccessible( + () -> { SystemSharedLib.loadLibrary("system_private2"); }); + TestUtils.assertLibraryInaccessible( + () -> { SystemSharedLib.loadLibrary("systemext_private2"); }); + } if (!TestUtils.skipPublicProductLibTests()) { TestUtils.assertLibraryInaccessible( @@ -83,12 +90,18 @@ public class DataAppTest extends AppTestCommon { @Test public void testLoadPrivateLibrariesViaSystemExtSharedLib() { - // TODO(b/237577392): Loading a private native system library via a shared system library - // ought to work. - TestUtils.assertLibraryInaccessible( - () -> SystemExtSharedLib.loadLibrary("system_private3")); - TestUtils.assertLibraryInaccessible( - () -> SystemExtSharedLib.loadLibrary("systemext_private3")); + if (TestUtils.canLoadPrivateLibsFromSamePartition()) { + // TODO(b/186729817): These loads work because the findLibrary call in + // loadLibrary0 in Runtime.java searches the system libs and converts + // them to absolute paths. + SystemExtSharedLib.loadLibrary("system_private3"); + SystemExtSharedLib.loadLibrary("systemext_private3"); + } else { + TestUtils.assertLibraryInaccessible( + () -> { SystemExtSharedLib.loadLibrary("system_private3"); }); + TestUtils.assertLibraryInaccessible( + () -> { SystemExtSharedLib.loadLibrary("systemext_private3"); }); + } if (!TestUtils.skipPublicProductLibTests()) { TestUtils.assertLibraryInaccessible( diff --git a/libnativeloader/test/src/android/test/app/ProductAppTest.java b/libnativeloader/test/src/android/test/app/ProductAppTest.java index 4cf379c9c6..a42d191f7b 100644 --- a/libnativeloader/test/src/android/test/app/ProductAppTest.java +++ b/libnativeloader/test/src/android/test/app/ProductAppTest.java @@ -72,14 +72,21 @@ public class ProductAppTest extends AppTestCommon { @Test public void testLoadPrivateLibrariesViaSystemSharedLib() { - if (!TestUtils.productAppsAreShared()) { - // TODO(b/237577392): Loading a private native system library via a shared system - // library ought to work. + if (TestUtils.productAppsAreShared() || TestUtils.canLoadPrivateLibsFromSamePartition()) { + // TODO(b/186729817): These loads work in the + // canLoadPrivateLibsFromSamePartition case because the findLibrary + // call in loadLibrary0 in Runtime.java searches the system libs and + // converts them to absolute paths. + SystemSharedLib.loadLibrary("system_private2"); + SystemSharedLib.loadLibrary("systemext_private2"); + } else { TestUtils.assertLibraryInaccessible( () -> SystemSharedLib.loadLibrary("system_private2")); TestUtils.assertLibraryInaccessible( () -> SystemSharedLib.loadLibrary("systemext_private2")); + } + if (!TestUtils.productAppsAreShared()) { TestUtils.assertLibraryInaccessible( () -> SystemSharedLib.loadLibrary("product_private2")); } @@ -89,14 +96,21 @@ public class ProductAppTest extends AppTestCommon { @Test public void testLoadPrivateLibrariesViaSystemExtSharedLib() { - if (!TestUtils.productAppsAreShared()) { - // TODO(b/237577392): Loading a private native system library via a shared system - // library ought to work. + if (TestUtils.productAppsAreShared() || TestUtils.canLoadPrivateLibsFromSamePartition()) { + // TODO(b/186729817): These loads work in the + // canLoadPrivateLibsFromSamePartition case because the findLibrary + // call in loadLibrary0 in Runtime.java searches the system libs and + // converts them to absolute paths. + SystemExtSharedLib.loadLibrary("system_private3"); + SystemExtSharedLib.loadLibrary("systemext_private3"); + } else { TestUtils.assertLibraryInaccessible( () -> SystemExtSharedLib.loadLibrary("system_private3")); TestUtils.assertLibraryInaccessible( () -> SystemExtSharedLib.loadLibrary("systemext_private3")); + } + if (!TestUtils.productAppsAreShared()) { TestUtils.assertLibraryInaccessible( () -> SystemExtSharedLib.loadLibrary("product_private3")); } diff --git a/libnativeloader/test/src/android/test/app/VendorAppTest.java b/libnativeloader/test/src/android/test/app/VendorAppTest.java index 377f670c74..b0e141c68b 100644 --- a/libnativeloader/test/src/android/test/app/VendorAppTest.java +++ b/libnativeloader/test/src/android/test/app/VendorAppTest.java @@ -71,11 +71,18 @@ public class VendorAppTest extends AppTestCommon { @Test public void testLoadPrivateLibrariesViaSystemSharedLib() { - // TODO(b/237577392): Loading a private native system library via a shared system library - // ought to work. - TestUtils.assertLibraryInaccessible(() -> SystemSharedLib.loadLibrary("system_private2")); - TestUtils.assertLibraryInaccessible( - () -> SystemSharedLib.loadLibrary("systemext_private2")); + if (TestUtils.canLoadPrivateLibsFromSamePartition()) { + // TODO(b/186729817): These loads work because the findLibrary call in + // loadLibrary0 in Runtime.java searches the system libs and converts + // them to absolute paths. + SystemSharedLib.loadLibrary("system_private2"); + SystemSharedLib.loadLibrary("systemext_private2"); + } else { + TestUtils.assertLibraryInaccessible( + () -> SystemSharedLib.loadLibrary("system_private2")); + TestUtils.assertLibraryInaccessible( + () -> SystemSharedLib.loadLibrary("systemext_private2")); + } if (!TestUtils.skipPublicProductLibTests()) { TestUtils.assertLibraryInaccessible( @@ -87,12 +94,18 @@ public class VendorAppTest extends AppTestCommon { @Test public void testLoadPrivateLibrariesViaSystemExtSharedLib() { - // TODO(b/237577392): Loading a private native system library via a shared system library - // ought to work. - TestUtils.assertLibraryInaccessible( - () -> SystemExtSharedLib.loadLibrary("system_private3")); - TestUtils.assertLibraryInaccessible( - () -> SystemExtSharedLib.loadLibrary("systemext_private3")); + if (TestUtils.canLoadPrivateLibsFromSamePartition()) { + // TODO(b/186729817): These loads work because the findLibrary call in + // loadLibrary0 in Runtime.java searches the system libs and converts + // them to absolute paths. + SystemExtSharedLib.loadLibrary("system_private3"); + SystemExtSharedLib.loadLibrary("systemext_private3"); + } else { + TestUtils.assertLibraryInaccessible( + () -> SystemExtSharedLib.loadLibrary("system_private3")); + TestUtils.assertLibraryInaccessible( + () -> SystemExtSharedLib.loadLibrary("systemext_private3")); + } if (!TestUtils.skipPublicProductLibTests()) { TestUtils.assertLibraryInaccessible( diff --git a/libnativeloader/test/src/android/test/lib/AppTestCommon.java b/libnativeloader/test/src/android/test/lib/AppTestCommon.java index 51f4655839..75d45b5ba7 100644 --- a/libnativeloader/test/src/android/test/lib/AppTestCommon.java +++ b/libnativeloader/test/src/android/test/lib/AppTestCommon.java @@ -41,7 +41,6 @@ public abstract class AppTestCommon { private boolean systemPrivateLibsAccessibleFromAppNamespace() { // Currently it only works from system apps. It also works from product // apps on old versions where they were treated like system apps. - // TODO(b/237577392): Fix this to work from system shared libs. return getAppLocation() == AppLocation.SYSTEM || (getAppLocation() == AppLocation.PRODUCT && TestUtils.productAppsAreShared()); } @@ -52,7 +51,6 @@ public abstract class AppTestCommon { // In old versions where product apps were treated like system apps, the // product private libs were included in the system namespace, so // they're accessible both from system and product apps. - // TODO(b/237577392): Fix this to work from product shared libs. return (getAppLocation() == AppLocation.SYSTEM || getAppLocation() == AppLocation.PRODUCT) && TestUtils.productAppsAreShared(); } @@ -60,7 +58,9 @@ public abstract class AppTestCommon { // Detect exception where we don't switch from a shared system namespace to // a product or vendor "unbundled" namespace when calling into // ProductSharedLib and VendorSharedLib. That means they still can load - // private system libs but not private libs in their own partition. + // private system libs but not private libs in their own partition (however + // the latter works anyway when canLoadPrivateLibsFromSamePartition() is + // true). // TODO(mast): Stop propagating the shared property (isBundledApp in // LoadedApk.java) down to public and vendor shared java libs? private boolean noSwitchToVendorOrProductNamespace() { @@ -72,7 +72,8 @@ public abstract class AppTestCommon { @Test public void testLoadPrivateLibrariesViaSystemSharedLibWithAbsolutePaths() { - if (systemPrivateLibsAccessibleFromAppNamespace()) { + if (TestUtils.canLoadPrivateLibsFromSamePartition() + || systemPrivateLibsAccessibleFromAppNamespace()) { SystemSharedLib.load(TestUtils.libPath("/system", "system_private7")); SystemSharedLib.load(TestUtils.libPath("/system_ext", "systemext_private7")); } else { @@ -98,7 +99,8 @@ public abstract class AppTestCommon { @Test public void testLoadPrivateLibrariesViaSystemExtSharedLibWithAbsolutePaths() { - if (systemPrivateLibsAccessibleFromAppNamespace()) { + if (TestUtils.canLoadPrivateLibsFromSamePartition() + || systemPrivateLibsAccessibleFromAppNamespace()) { SystemExtSharedLib.load(TestUtils.libPath("/system", "system_private8")); SystemExtSharedLib.load(TestUtils.libPath("/system_ext", "systemext_private8")); } else { @@ -145,7 +147,8 @@ public abstract class AppTestCommon { loadPrivateProductLib = getAppLocation() == AppLocation.SYSTEM || getAppLocation() == AppLocation.PRODUCT; } else { - loadPrivateProductLib = !noSwitchToVendorOrProductNamespace(); + loadPrivateProductLib = TestUtils.canLoadPrivateLibsFromSamePartition() + || !noSwitchToVendorOrProductNamespace(); } if (loadPrivateProductLib) { ProductSharedLib.load(TestUtils.libPath("/product", "product_private9")); @@ -181,7 +184,8 @@ public abstract class AppTestCommon { }); } - if (!noSwitchToVendorOrProductNamespace()) { + if (TestUtils.canLoadPrivateLibsFromSamePartition() + || !noSwitchToVendorOrProductNamespace()) { VendorSharedLib.load(TestUtils.libPath("/vendor", "vendor_private10")); } else { TestUtils.assertLibraryInaccessible(() -> { diff --git a/libnativeloader/test/src/android/test/lib/TestUtils.java b/libnativeloader/test/src/android/test/lib/TestUtils.java index 5f5cd911e8..00b486e34c 100644 --- a/libnativeloader/test/src/android/test/lib/TestUtils.java +++ b/libnativeloader/test/src/android/test/lib/TestUtils.java @@ -55,6 +55,12 @@ public final class TestUtils { return !SdkLevel.isAtLeastU() && SystemProperties.get("ro.product.vndk.version").isEmpty(); } + // True if apps and shared java libs in system/product/vendor partitions are + // able to load private native libs in the same partition. + public static boolean canLoadPrivateLibsFromSamePartition() { + return SdkLevel.isAtLeastV(); + } + // Test that private libs are present, as a safeguard so that the dlopen // failures we expect in other tests aren't due to them not being there. public static void testPrivateLibsExist(String libDir, String libStem) { diff --git a/runtime/jni/java_vm_ext.cc b/runtime/jni/java_vm_ext.cc index 2a364f37b1..bbe3970839 100644 --- a/runtime/jni/java_vm_ext.cc +++ b/runtime/jni/java_vm_ext.cc @@ -958,12 +958,12 @@ bool JavaVMExt::LoadNativeLibrary(JNIEnv* env, if (class_linker->IsBootClassLoader(loader)) { loader = nullptr; class_loader = nullptr; - if (caller_class != nullptr) { - ObjPtr<mirror::Class> caller = soa.Decode<mirror::Class>(caller_class); - ObjPtr<mirror::DexCache> dex_cache = caller->GetDexCache(); - if (dex_cache != nullptr) { - caller_location = dex_cache->GetLocation()->ToModifiedUtf8(); - } + } + if (caller_class != nullptr) { + ObjPtr<mirror::Class> caller = soa.Decode<mirror::Class>(caller_class); + ObjPtr<mirror::DexCache> dex_cache = caller->GetDexCache(); + if (dex_cache != nullptr) { + caller_location = dex_cache->GetLocation()->ToModifiedUtf8(); } } |