summaryrefslogtreecommitdiff
path: root/libnativeloader/library_namespaces.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libnativeloader/library_namespaces.cpp')
-rw-r--r--libnativeloader/library_namespaces.cpp158
1 files changed, 90 insertions, 68 deletions
diff --git a/libnativeloader/library_namespaces.cpp b/libnativeloader/library_namespaces.cpp
index f31c4302a4..1e29f4e457 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_treblelized()) {
+ 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
@@ -383,8 +406,7 @@ Result<NativeLoaderNamespace*> LibraryNamespaces::Create(JNIEnv* env, uint32_t t
product_public_libraries());
if (!product_libs.empty()) {
auto target_ns = system_ns;
- if (is_product_vndk_version_defined()) {
- // If ro.product.vndk.version is defined, product namespace provides the product libraries.
+ if (is_product_treblelized()) {
target_ns = NativeLoaderNamespace::GetExportedNamespace(kProductNamespaceName, is_bridged);
}
if (target_ns.ok()) {