From 26335f89b1b25fd386adbc89edfcc600191b9e07 Mon Sep 17 00:00:00 2001 From: Jiyong Park Date: Tue, 22 Aug 2017 10:25:18 +0900 Subject: [PATCH 1/2] add llndk|vndksp.libraries.txt to vndk_package List of llndk and vndk-sp libraries are written in the txt file so that they can be available at run-time. The information is used by libnativeloader to configure the classloader-namespace specially for vendor apks. Bug: 64882323 Test: build 2017 pixel devices. check that the two files exist on /system/etc. Change-Id: Ifbe339a5862f6ef57a8213a14a022765ccf77283 --- rootdir/Android.mk | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/rootdir/Android.mk b/rootdir/Android.mk index 3ddf9769e..6cfbe20d4 100644 --- a/rootdir/Android.mk +++ b/rootdir/Android.mk @@ -247,3 +247,45 @@ LOCAL_MODULE_PATH := $(TARGET_OUT_ETC) LOCAL_MODULE_STEM := $(LOCAL_MODULE) include $(BUILD_PREBUILT) endif + +####################################### +# llndk.libraries.txt +include $(CLEAR_VARS) +LOCAL_MODULE := llndk.libraries.txt +LOCAL_MODULE_CLASS := ETC +LOCAL_MODULE_PATH := $(TARGET_OUT_ETC) +LOCAL_MODULE_STEM := $(LOCAL_MODULE) +include $(BUILD_SYSTEM)/base_rules.mk +llndk_md5 = $(word 1, $(shell echo $(LLNDK_LIBRARIES) | $(MD5SUM))) +llndk_dep = $(intermediates)/$(llndk_md5).dep +$(llndk_dep): + $(hide) mkdir -p $(dir $@) && rm -rf $(dir $@)*.dep && touch $@ + +$(LOCAL_BUILT_MODULE): PRIVATE_LLNDK_LIBRARIES := $(LLNDK_LIBRARIES) +$(LOCAL_BUILT_MODULE): $(llndk_dep) + @echo "Generate: $@" + @mkdir -p $(dir $@) + $(hide) echo -n > $@ + $(hide) $(foreach lib,$(PRIVATE_LLNDK_LIBRARIES), \ + echo $(lib).so >> $@;) + +####################################### +# vndksp.libraries.txt +include $(CLEAR_VARS) +LOCAL_MODULE := vndksp.libraries.txt +LOCAL_MODULE_CLASS := ETC +LOCAL_MODULE_PATH := $(TARGET_OUT_ETC) +LOCAL_MODULE_STEM := $(LOCAL_MODULE) +include $(BUILD_SYSTEM)/base_rules.mk +vndksp_md5 = $(word 1, $(shell echo $(LLNDK_LIBRARIES) | $(MD5SUM))) +vndksp_dep = $(intermediates)/$(vndksp_md5).dep +$(vndksp_dep): + $(hide) mkdir -p $(dir $@) && rm -rf $(dir $@)*.dep && touch $@ + +$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_SAMEPROCESS_LIBRARIES := $(VNDK_SAMEPROCESS_LIBRARIES) +$(LOCAL_BUILT_MODULE): $(vndksp_dep) + @echo "Generate: $@" + @mkdir -p $(dir $@) + $(hide) echo -n > $@ + $(hide) $(foreach lib,$(PRIVATE_VNDK_SAMEPROCESS_LIBRARIES), \ + echo $(lib).so >> $@;) From a07f3057d00a1da240099aa77d55aaf83362c489 Mon Sep 17 00:00:00 2001 From: Jiyong Park Date: Tue, 22 Aug 2017 10:26:10 +0900 Subject: [PATCH 2/2] vendor apk is unbundled For devices where VNDK restrictions are all enforced, vendor apks are recognized as unbundled; since system partition and vendor partition can be updated independently from each other. However, since vendor apks are still bundled in the vendor partition, they are allowed to do more than ordinaly unbundled apks that are downloaded and installed to the data partition. 1) /vendor/lib is allowed. So the path is added to the search_paths and permitted paths of the classloader namespace. 2) LLNDK libs are allowed in addition to the NDK libs. So, LLNDK lib list from llndk.libraries.txt is added to the list from public.libraries.txt. 3) VNDK-SP libs are allowed. To do so, the classloader namespace is linked to the 'vndk' namespace where VNDK-SP libs are searched and loaded from. The list of available VNDK-SP libs is read from vndksp.libraries.txt file. 4) Name of the namespace is changed to 'vendor-classloader-namespace' since the namespace is configured differently from the ordinary 'classloader-namespace'. Bug: 63553457 Test: 2017 pixel devices build and boots to the UI Test: a vendor apk (e.g. TimeService.apk) works. Turn the airplain mode on. Set time. Reboot the device. The time is not reset. Test: 1) set target as 2017 pixel 2) m -j CtsVendorJniTestCases 3) copy the built apk into /vendor/app/CtsVendorJniTestCases 4) reboot / factory reset 5) adb shell am instrument -w android.jni.vendor.cts Change-Id: I447452eb025c0a0fd076b5c9ac081d453dc6074e --- .../include/nativeloader/native_loader.h | 1 + libnativeloader/native_loader.cpp | 78 +++++++++++++++++-- rootdir/etc/ld.config.txt.in | 9 +-- 3 files changed, 76 insertions(+), 12 deletions(-) diff --git a/libnativeloader/include/nativeloader/native_loader.h b/libnativeloader/include/nativeloader/native_loader.h index 99ae3a759..3563fc149 100644 --- a/libnativeloader/include/nativeloader/native_loader.h +++ b/libnativeloader/include/nativeloader/native_loader.h @@ -34,6 +34,7 @@ jstring CreateClassLoaderNamespace(JNIEnv* env, int32_t target_sdk_version, jobject class_loader, bool is_shared, + bool is_for_vendor, jstring library_path, jstring permitted_path); diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp index 7ccd7db95..5d160eee7 100644 --- a/libnativeloader/native_loader.cpp +++ b/libnativeloader/native_loader.cpp @@ -82,6 +82,11 @@ static constexpr const char* kPublicNativeLibrariesSystemConfigPathFromRoot = "/etc/public.libraries.txt"; static constexpr const char* kPublicNativeLibrariesVendorConfig = "/vendor/etc/public.libraries.txt"; +static constexpr const char* kLlndkNativeLibrariesSystemConfigPathFromRoot = + "/etc/llndk.libraries.txt"; +static constexpr const char* kVndkspNativeLibrariesSystemConfigPathFromRoot = + "/etc/vndksp.libraries.txt"; + // The device may be configured to have the vendor libraries loaded to a separate namespace. // For historical reasons this namespace was named sphal but effectively it is intended @@ -89,6 +94,11 @@ static constexpr const char* kPublicNativeLibrariesVendorConfig = // vendor and system namespaces. static constexpr const char* kVendorNamespaceName = "sphal"; +static constexpr const char* kVndkNamespaceName = "vndk"; + +static constexpr const char* kClassloaderNamespaceName = "classloader-namespace"; +static constexpr const char* kVendorClassloaderNamespaceName = "vendor-classloader-namespace"; + // (http://b/27588281) This is a workaround for apps using custom classloaders and calling // System.load() with an absolute path which is outside of the classloader library search path. // This list includes all directories app is allowed to access this way. @@ -108,6 +118,7 @@ class LibraryNamespaces { uint32_t target_sdk_version, jobject class_loader, bool is_shared, + bool is_for_vendor, jstring java_library_path, jstring java_permitted_path, NativeLoaderNamespace* ns, @@ -163,9 +174,39 @@ class LibraryNamespaces { is_native_bridge = NativeBridgeIsPathSupported(library_path.c_str()); } + std::string system_exposed_libraries = system_public_libraries_; + const char* namespace_name = kClassloaderNamespaceName; + android_namespace_t* vndk_ns = nullptr; + if (is_for_vendor && !is_shared) { + LOG_FATAL_IF(is_native_bridge, "Unbundled vendor apk must not use translated architecture"); + + // For vendor apks, give access to the vendor lib even though + // they are treated as unbundled; the libs and apks are still bundled + // together in the vendor partition. +#if defined(__LP64__) + std::string vendor_lib_path = "/vendor/lib64"; +#else + std::string vendor_lib_path = "/vendor/lib"; +#endif + library_path = library_path + ":" + vendor_lib_path.c_str(); + permitted_path = permitted_path + ":" + vendor_lib_path.c_str(); + + // Also give access to LLNDK libraries since they are available to vendors + system_exposed_libraries = system_exposed_libraries + ":" + system_llndk_libraries_.c_str(); + + // Give access to VNDK-SP libraries from the 'vndk' namespace. + vndk_ns = android_get_exported_namespace(kVndkNamespaceName); + LOG_ALWAYS_FATAL_IF(vndk_ns == nullptr, + "Cannot find \"%s\" namespace for vendor apks", kVndkNamespaceName); + + // Different name is useful for debugging + namespace_name = kVendorClassloaderNamespaceName; + ALOGD("classloader namespace configured for unbundled vendor apk. library_path=%s", library_path.c_str()); + } + NativeLoaderNamespace native_loader_ns; if (!is_native_bridge) { - android_namespace_t* ns = android_create_namespace("classloader-namespace", + android_namespace_t* ns = android_create_namespace(namespace_name, nullptr, library_path.c_str(), namespace_type, @@ -181,11 +222,19 @@ class LibraryNamespaces { // which is expected behavior in this case. android_namespace_t* vendor_ns = android_get_exported_namespace(kVendorNamespaceName); - if (!android_link_namespaces(ns, nullptr, system_public_libraries_.c_str())) { + if (!android_link_namespaces(ns, nullptr, system_exposed_libraries.c_str())) { *error_msg = dlerror(); return false; } + if (vndk_ns != nullptr && !system_vndksp_libraries_.empty()) { + // vendor apks are allowed to use VNDK-SP libraries. + if (!android_link_namespaces(ns, vndk_ns, system_vndksp_libraries_.c_str())) { + *error_msg = dlerror(); + return false; + } + } + if (!vendor_public_libraries_.empty()) { if (!android_link_namespaces(ns, vendor_ns, vendor_public_libraries_.c_str())) { *error_msg = dlerror(); @@ -195,7 +244,7 @@ class LibraryNamespaces { native_loader_ns = NativeLoaderNamespace(ns); } else { - native_bridge_namespace_t* ns = NativeBridgeCreateNamespace("classloader-namespace", + native_bridge_namespace_t* ns = NativeBridgeCreateNamespace(namespace_name, nullptr, library_path.c_str(), namespace_type, @@ -209,7 +258,7 @@ class LibraryNamespaces { native_bridge_namespace_t* vendor_ns = NativeBridgeGetVendorNamespace(); - if (!NativeBridgeLinkNamespaces(ns, nullptr, system_public_libraries_.c_str())) { + if (!NativeBridgeLinkNamespaces(ns, nullptr, system_exposed_libraries.c_str())) { *error_msg = NativeBridgeGetError(); return false; } @@ -259,6 +308,10 @@ class LibraryNamespaces { std::string root_dir = android_root_env != nullptr ? android_root_env : "/system"; std::string public_native_libraries_system_config = root_dir + kPublicNativeLibrariesSystemConfigPathFromRoot; + std::string llndk_native_libraries_system_config = + root_dir + kLlndkNativeLibrariesSystemConfigPathFromRoot; + std::string vndksp_native_libraries_system_config = + root_dir + kVndkspNativeLibrariesSystemConfigPathFromRoot; std::string error_msg; LOG_ALWAYS_FATAL_IF(!ReadConfig(public_native_libraries_system_config, &sonames, &error_msg), @@ -293,6 +346,14 @@ class LibraryNamespaces { system_public_libraries_ = base::Join(sonames, ':'); + sonames.clear(); + ReadConfig(kLlndkNativeLibrariesSystemConfigPathFromRoot, &sonames); + system_llndk_libraries_ = base::Join(sonames, ':'); + + sonames.clear(); + ReadConfig(kVndkspNativeLibrariesSystemConfigPathFromRoot, &sonames); + system_vndksp_libraries_ = base::Join(sonames, ':'); + sonames.clear(); // This file is optional, quietly ignore if the file does not exist. ReadConfig(kPublicNativeLibrariesVendorConfig, &sonames); @@ -404,6 +465,8 @@ class LibraryNamespaces { std::vector> namespaces_; std::string system_public_libraries_; std::string vendor_public_libraries_; + std::string system_llndk_libraries_; + std::string system_vndksp_libraries_; DISALLOW_COPY_AND_ASSIGN(LibraryNamespaces); }; @@ -430,6 +493,7 @@ jstring CreateClassLoaderNamespace(JNIEnv* env, int32_t target_sdk_version, jobject class_loader, bool is_shared, + bool is_for_vendor, jstring library_path, jstring permitted_path) { #if defined(__ANDROID__) @@ -441,6 +505,7 @@ jstring CreateClassLoaderNamespace(JNIEnv* env, target_sdk_version, class_loader, is_shared, + is_for_vendor, library_path, permitted_path, &ns, @@ -449,7 +514,7 @@ jstring CreateClassLoaderNamespace(JNIEnv* env, return env->NewStringUTF(error_msg.c_str()); } #else - UNUSED(env, target_sdk_version, class_loader, is_shared, + UNUSED(env, target_sdk_version, class_loader, is_shared, is_for_vendor, library_path, permitted_path); #endif return nullptr; @@ -478,7 +543,8 @@ void* OpenNativeLibrary(JNIEnv* env, if (!g_namespaces->Create(env, target_sdk_version, class_loader, - false, + false /* is_shared */, + false /* is_for_vendor */, library_path, nullptr, &ns, diff --git a/rootdir/etc/ld.config.txt.in b/rootdir/etc/ld.config.txt.in index 401b0341b..7e23a850f 100644 --- a/rootdir/etc/ld.config.txt.in +++ b/rootdir/etc/ld.config.txt.in @@ -27,16 +27,12 @@ additional.namespaces = sphal,vndk,rs # can't be loaded in this namespace. ############################################################################### namespace.default.isolated = true -# TODO(b/63553457): remove /vendor/lib from the search path. For now, this is -# required since the classloader namespace for vendor apks should have access -# vendor libraries in the directory. These search paths are copied to the search -# paths of the classloader namespace. -namespace.default.search.paths = /system/${LIB}:/vendor/${LIB} +namespace.default.search.paths = /system/${LIB} # /vendor/app, /vendor/framework were added since libart should be able to dlopen # the odex files from the directory. namespace.default.permitted.paths = /system/${LIB}/drm:/system/${LIB}/hw:/system/framework:/system/app:/system/priv-app:/vendor/app:/vendor/framework:/oem/app:/data:/mnt/expand -namespace.default.asan.search.paths = /data/asan/system/${LIB}:/system/${LIB}:/data/asan/vendor/${LIB}:/vendor/${LIB} +namespace.default.asan.search.paths = /data/asan/system/${LIB}:/system/${LIB} namespace.default.asan.permitted.paths = /data:/system/${LIB}/drm:/system/${LIB}/hw:/system/framework:/system/app:/system/priv-app:/vendor/app:/vendor/framework:/oem/app:/mnt/expand ############################################################################### @@ -99,6 +95,7 @@ namespace.rs.link.vndk.shared_libs = %VNDK_SAMEPROCESS_LIBRARIES% # This namespace is exclusively for vndk-sp libs. ############################################################################### namespace.vndk.isolated = true +namespace.vndk.visible = true namespace.vndk.search.paths = /vendor/${LIB}/vndk-sp:/system/${LIB}/vndk-sp namespace.vndk.permitted.paths = /vendor/${LIB}/hw:/vendor/${LIB}/egl