summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Martin Stjernholm <mast@google.com> 2024-01-29 19:57:04 +0000
committer Treehugger Robot <android-test-infra-autosubmit@system.gserviceaccount.com> 2024-02-23 16:47:38 +0000
commit6e52064e41e6a130f1713c2f422c5bf66a5ff3b7 (patch)
tree42e65b1bff99218ce71ea1e6d6a2adb140d88ec5
parentf250d0b4c066d6993266b237c81515ed934fae6f (diff)
Give full access to native libs from java libs in the same partition
(reland). For both packages and shared java libs in system image partitions (system, product, vendor), load native libraries from the same partition by using the linker namespace for that partition ("default" or "system", "product", "sphal", respectively). This is only done for native libraries in the <partition root>/lib(64) directories when specified by an absolute path (i.e. use java.lang.System.load rather than loadLibrary). Otherwise it's looked up using the classloader namespace for the package, as before. Since only loads with absolute paths are affected, compat issues are unlikely. However to be on the safe side it's only enabled for SDK level 35 (VIC) and later (regardless of targetSdkVersion of the package, because the affected code is in system image partitions). This is based on a reland of commit 453b9fe909c22eb0f01b3072a5213dd46aed6f45, but with a different solution. It also extends the approach to work for vendor and product partitions. Test: atest libnativeloader_e2e_tests \ libnativeloader_test libnativeloader_lazy_test Test: libnativeloader_e2e_tests on S, Sv2, T, and U platforms in CI Bug: 237577392 Change-Id: If8b74503edfa9229b9eada73968b7d7b5c75ca10
-rw-r--r--libnativeloader/Android.bp2
-rw-r--r--libnativeloader/library_namespaces.cpp4
-rw-r--r--libnativeloader/library_namespaces.h1
-rw-r--r--libnativeloader/library_namespaces_test.cpp41
-rw-r--r--libnativeloader/native_loader.cpp78
-rw-r--r--libnativeloader/test/src/android/test/app/DataAppTest.java35
-rw-r--r--libnativeloader/test/src/android/test/app/ProductAppTest.java26
-rw-r--r--libnativeloader/test/src/android/test/app/VendorAppTest.java35
-rw-r--r--libnativeloader/test/src/android/test/lib/AppTestCommon.java18
-rw-r--r--libnativeloader/test/src/android/test/lib/TestUtils.java6
-rw-r--r--runtime/jni/java_vm_ext.cc12
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();
}
}