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-03-18 14:05:45 +0000
commit899c4295652ba6c954c1dc590f9c288849f9119c (patch)
treeba8d87755d6647710ff717568ab798a1d406e9ef
parent418b58fe9c94a4bc2592d27b45a8e44c70742119 (diff)
Give full access to native libs from Java libs in the same partition
(reland 2). 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 relands https://r.android.com/2933611 but keeps the vendor and product API domain checks unchanged in the CreateClassLoaderNamespace code paths (cf. b/326631342). Test: atest libnativeloader_e2e_tests \ libnativeloader_test libnativeloader_lazy_test Test: libnativeloader_e2e_tests on S, Sv2, T, and U platforms in CI Test: ImsServiceEntitlementUnitTests Bug: 237577392 Change-Id: I246101c1663d81089d9b4ae9450c28d564a7603a
-rw-r--r--libnativeloader/Android.bp2
-rw-r--r--libnativeloader/library_namespaces.cpp21
-rw-r--r--libnativeloader/library_namespaces.h1
-rw-r--r--libnativeloader/library_namespaces_test.cpp56
-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, 222 insertions, 68 deletions
diff --git a/libnativeloader/Android.bp b/libnativeloader/Android.bp
index 9d8fdb153c..9e298f5400 100644
--- a/libnativeloader/Android.bp
+++ b/libnativeloader/Android.bp
@@ -56,6 +56,7 @@ art_cc_library {
"native_loader.cpp",
],
header_libs: [
+ "art_libartbase_headers",
"libnativehelper_header_only",
],
shared_libs: [
@@ -88,6 +89,7 @@ art_cc_library {
],
static_libs: [
"libPlatformProperties",
+ "libmodules-utils-build",
],
},
},
diff --git a/libnativeloader/library_namespaces.cpp b/libnativeloader/library_namespaces.cpp
index e2b27294f9..7b18b15dd0 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,11 +104,15 @@ 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;
}
// Returns the API domain for a ':'-separated list of paths, or an error if they
-// match more than one.
+// match more than one. This function does not recognize API_DOMAIN_SYSTEM and
+// will return API_DOMAIN_DEFAULT instead.
Result<ApiDomain> GetApiDomainFromPathList(const std::string& path_list) {
ApiDomain result = API_DOMAIN_DEFAULT;
size_t start_pos = 0;
@@ -115,13 +120,13 @@ Result<ApiDomain> GetApiDomainFromPathList(const std::string& path_list) {
size_t end_pos = path_list.find(':', start_pos);
ApiDomain api_domain =
GetApiDomainFromPath(std::string_view(path_list).substr(start_pos, end_pos));
- // Allow mixing API_DOMAIN_DEFAULT with any other domain. That's a bit lax,
- // since the default e.g. includes /data, which strictly speaking is a
- // separate domain. However, we keep it this way to not risk compat issues
- // until we actually need all domains.
- if (api_domain != API_DOMAIN_DEFAULT) {
- if (result != API_DOMAIN_DEFAULT && result != api_domain) {
- return Error() << "Path list crosses partition boundaries: " << path_list;
+ if (api_domain == API_DOMAIN_VENDOR || api_domain == API_DOMAIN_PRODUCT) {
+ if ((result == API_DOMAIN_VENDOR || result == API_DOMAIN_PRODUCT) && result != api_domain) {
+ // Fail only if the path list has both vendor and product paths. Allow
+ // combinations of either with API_DOMAIN_SYSTEM and API_DOMAIN_DEFAULT,
+ // because the path list we get here may contain shared Java system
+ // libraries and app APKs which may be in /data.
+ return Error() << "Path list crosses vendor/product partition boundaries: " << path_list;
}
result = api_domain;
}
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..4582223f4a 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_ext/somewhere"), HasValue(API_DOMAIN_DEFAULT));
+ 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_DEFAULT)));
EXPECT_THAT(GetApiDomainFromPathList("/system/vendor/somewhere"), HasValue(API_DOMAIN_VENDOR));
EXPECT_THAT(GetApiDomainFromPathList(""), HasValue(API_DOMAIN_DEFAULT));
@@ -73,12 +78,25 @@ 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) {
- 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"))));
+ HasValue(GetProductApiDomain(API_DOMAIN_DEFAULT)));
+ EXPECT_THAT(GetApiDomainFromPathList("/system/somewhere:/product/somewhere"),
+ HasValue(GetProductApiDomain(API_DOMAIN_DEFAULT)));
+ EXPECT_THAT(GetApiDomainFromPathList("/product/somewhere:/system/somewhere"),
+ HasValue(GetProductApiDomain(API_DOMAIN_DEFAULT)));
+ EXPECT_THAT(GetApiDomainFromPathList("/data/somewhere:/vendor/somewhere"),
+ HasValue(API_DOMAIN_VENDOR));
+ EXPECT_THAT(GetApiDomainFromPathList("/system/somewhere:/vendor/somewhere"),
+ HasValue(API_DOMAIN_VENDOR));
+ EXPECT_THAT(GetApiDomainFromPathList("/vendor/somewhere:/system/somewhere"),
+ HasValue(API_DOMAIN_VENDOR));
+
+ if (GetProductApiDomain(API_DOMAIN_DEFAULT) == API_DOMAIN_PRODUCT) {
+ EXPECT_THAT(
+ GetApiDomainFromPathList("/vendor/somewhere:/product/somewhere"),
+ HasError(WithMessage(StartsWith("Path list crosses vendor/product partition boundaries"))));
+ EXPECT_THAT(
+ GetApiDomainFromPathList("/system/somewhere:/product/somewhere:/vendor/somewhere"),
+ HasError(WithMessage(StartsWith("Path list crosses vendor/product partition boundaries"))));
}
}
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..f91eab230a 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();
}
}