From 40a6077244e22b5f3ab96358210b636618d4121a Mon Sep 17 00:00:00 2001 From: Jiyong Park Date: Fri, 3 May 2019 16:21:31 +0900 Subject: [PATCH 1/3] Move public libraries list to a separate source file Functions for reading the public libraries list are moved out of library_namespace.cpp to public_libraries.cpp. In addition, library-local symbols are moved from android namespace to android::nativeloader namespace. Bug: 130388701 Test: build & pass presubmit tests Change-Id: If82419598304d56d29bfec4ef553443c788d0f53 --- libnativeloader/Android.bp | 1 + libnativeloader/library_namespaces.cpp | 274 ++------------------- libnativeloader/library_namespaces.h | 13 +- libnativeloader/native_loader.cpp | 2 + libnativeloader/public_libraries.cpp | 322 +++++++++++++++++++++++++ libnativeloader/public_libraries.h | 34 +++ 6 files changed, 383 insertions(+), 263 deletions(-) create mode 100644 libnativeloader/public_libraries.cpp create mode 100644 libnativeloader/public_libraries.h diff --git a/libnativeloader/Android.bp b/libnativeloader/Android.bp index 4d65b5027..3b77a9e9f 100644 --- a/libnativeloader/Android.bp +++ b/libnativeloader/Android.bp @@ -30,6 +30,7 @@ cc_library { android: { srcs: [ "library_namespaces.cpp", + "public_libraries.cpp", ], shared_libs: [ "libdl_android", diff --git a/libnativeloader/library_namespaces.cpp b/libnativeloader/library_namespaces.cpp index 3c4911f33..b80e9a1b6 100644 --- a/libnativeloader/library_namespaces.cpp +++ b/libnativeloader/library_namespaces.cpp @@ -29,28 +29,11 @@ #include "android-base/strings.h" #include "nativehelper/ScopedUtfChars.h" #include "nativeloader/dlext_namespaces.h" +#include "public_libraries.h" -namespace android { +namespace android::nativeloader { namespace { -using namespace std::string_literals; - -constexpr const char kPublicNativeLibrariesSystemConfigPathFromRoot[] = "/etc/public.libraries.txt"; -constexpr const char kPublicNativeLibrariesExtensionConfigPrefix[] = "public.libraries-"; -constexpr const size_t kPublicNativeLibrariesExtensionConfigPrefixLen = - sizeof(kPublicNativeLibrariesExtensionConfigPrefix) - 1; -constexpr const char kPublicNativeLibrariesExtensionConfigSuffix[] = ".txt"; -constexpr const size_t kPublicNativeLibrariesExtensionConfigSuffixLen = - sizeof(kPublicNativeLibrariesExtensionConfigSuffix) - 1; -constexpr const char kPublicNativeLibrariesVendorConfig[] = "/vendor/etc/public.libraries.txt"; -constexpr const char kLlndkNativeLibrariesSystemConfigPathFromRoot[] = "/etc/llndk.libraries.txt"; -constexpr const char kVndkspNativeLibrariesSystemConfigPathFromRoot[] = "/etc/vndksp.libraries.txt"; - -const std::vector kRuntimePublicLibraries = { - "libicuuc.so", - "libicui18n.so", -}; - // 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 // to use to load vendor libraries to separate namespace with controlled interface between @@ -78,12 +61,11 @@ constexpr const char* kVendorClassloaderNamespaceName = "vendor-classloader-name // This list includes all directories app is allowed to access this way. constexpr const char* kWhitelistedDirectories = "/data:/mnt/expand"; +// TODO(b/130388701) use macro LIB to eliminate the conditional #if defined(__LP64__) -constexpr const char* kRuntimeApexLibPath = "/apex/com.android.runtime/lib64"; constexpr const char* kVendorLibPath = "/vendor/lib64"; constexpr const char* kProductLibPath = "/product/lib64:/system/product/lib64"; #else -constexpr const char* kRuntimeApexLibPath = "/apex/com.android.runtime/lib"; constexpr const char* kVendorLibPath = "/vendor/lib"; constexpr const char* kProductLibPath = "/product/lib:/system/product/lib"; #endif @@ -98,146 +80,6 @@ typedef enum { APK_ORIGIN_PRODUCT = 2, } ApkOrigin; -bool is_debuggable() { - bool debuggable = false; - debuggable = android::base::GetBoolProperty("ro.debuggable", false); - return debuggable; -} - -std::string vndk_version_str() { - std::string version = android::base::GetProperty("ro.vndk.version", ""); - if (version != "" && version != "current") { - return "." + version; - } - return ""; -} - -void insert_vndk_version_str(std::string* file_name) { - CHECK(file_name != nullptr); - size_t insert_pos = file_name->find_last_of("."); - if (insert_pos == std::string::npos) { - insert_pos = file_name->length(); - } - file_name->insert(insert_pos, vndk_version_str()); -} - -const std::function always_true = - [](const std::string&, std::string*) { return true; }; - -bool ReadConfig(const std::string& configFile, std::vector* sonames, - const std::function& check_soname, - std::string* error_msg = nullptr) { - // Read list of public native libraries from the config file. - std::string file_content; - if (!base::ReadFileToString(configFile, &file_content)) { - if (error_msg) *error_msg = strerror(errno); - return false; - } - - std::vector lines = base::Split(file_content, "\n"); - - for (auto& line : lines) { - auto trimmed_line = base::Trim(line); - if (trimmed_line[0] == '#' || trimmed_line.empty()) { - continue; - } - size_t space_pos = trimmed_line.rfind(' '); - if (space_pos != std::string::npos) { - std::string type = trimmed_line.substr(space_pos + 1); - if (type != "32" && type != "64") { - if (error_msg) *error_msg = "Malformed line: " + line; - return false; - } -#if defined(__LP64__) - // Skip 32 bit public library. - if (type == "32") { - continue; - } -#else - // Skip 64 bit public library. - if (type == "64") { - continue; - } -#endif - trimmed_line.resize(space_pos); - } - - if (check_soname(trimmed_line, error_msg)) { - sonames->push_back(trimmed_line); - } else { - return false; - } - } - return true; -} - -void ReadExtensionLibraries(const char* dirname, std::vector* sonames) { - std::unique_ptr dir(opendir(dirname), closedir); - if (dir != nullptr) { - // Failing to opening the dir is not an error, which can happen in - // webview_zygote. - while (struct dirent* ent = readdir(dir.get())) { - if (ent->d_type != DT_REG && ent->d_type != DT_LNK) { - continue; - } - const std::string filename(ent->d_name); - if (android::base::StartsWith(filename, kPublicNativeLibrariesExtensionConfigPrefix) && - android::base::EndsWith(filename, kPublicNativeLibrariesExtensionConfigSuffix)) { - const size_t start = kPublicNativeLibrariesExtensionConfigPrefixLen; - const size_t end = filename.size() - kPublicNativeLibrariesExtensionConfigSuffixLen; - const std::string company_name = filename.substr(start, end - start); - const std::string config_file_path = dirname + "/"s + filename; - LOG_ALWAYS_FATAL_IF( - company_name.empty(), - "Error extracting company name from public native library list file path \"%s\"", - config_file_path.c_str()); - - std::string error_msg; - - LOG_ALWAYS_FATAL_IF( - !ReadConfig(config_file_path, sonames, - [&company_name](const std::string& soname, std::string* error_msg) { - if (android::base::StartsWith(soname, "lib") && - android::base::EndsWith(soname, "." + company_name + ".so")) { - return true; - } else { - *error_msg = "Library name \"" + soname + - "\" does not end with the company name: " + company_name + - "."; - return false; - } - }, - &error_msg), - "Error reading public native library list from \"%s\": %s", config_file_path.c_str(), - error_msg.c_str()); - } - } - } -} - -/** - * Remove the public libs in runtime namespace - */ -void removePublicLibsIfExistsInRuntimeApex(std::vector& sonames) { - for (const std::string& lib_name : kRuntimePublicLibraries) { - std::string path(kRuntimeApexLibPath); - path.append("/").append(lib_name); - - struct stat s; - // Do nothing if the path in /apex does not exist. - // Runtime APEX must be mounted since libnativeloader is in the same APEX - if (stat(path.c_str(), &s) != 0) { - continue; - } - - auto it = std::find(sonames.begin(), sonames.end(), lib_name); - if (it != sonames.end()) { - sonames.erase(it); - } - } -} - jobject GetParentClassLoader(JNIEnv* env, jobject class_loader) { jclass class_loader_class = env->FindClass("java/lang/ClassLoader"); jmethodID get_parent = @@ -277,48 +119,6 @@ void LibraryNamespaces::Initialize() { return; } - std::vector sonames; - const char* android_root_env = getenv("ANDROID_ROOT"); - std::string root_dir = android_root_env != nullptr ? android_root_env : "/system"; - std::string public_native_libraries_system_config = - root_dir + kPublicNativeLibrariesSystemConfigPathFromRoot; - std::string runtime_public_libraries = base::Join(kRuntimePublicLibraries, ":"); - std::string llndk_native_libraries_system_config = - root_dir + kLlndkNativeLibrariesSystemConfigPathFromRoot; - std::string vndksp_native_libraries_system_config = - root_dir + kVndkspNativeLibrariesSystemConfigPathFromRoot; - - std::string product_public_native_libraries_dir = "/product/etc"; - - std::string error_msg; - LOG_ALWAYS_FATAL_IF( - !ReadConfig(public_native_libraries_system_config, &sonames, always_true, &error_msg), - "Error reading public native library list from \"%s\": %s", - public_native_libraries_system_config.c_str(), error_msg.c_str()); - - // For debuggable platform builds use ANDROID_ADDITIONAL_PUBLIC_LIBRARIES environment - // variable to add libraries to the list. This is intended for platform tests only. - if (is_debuggable()) { - const char* additional_libs = getenv("ANDROID_ADDITIONAL_PUBLIC_LIBRARIES"); - if (additional_libs != nullptr && additional_libs[0] != '\0') { - std::vector additional_libs_vector = base::Split(additional_libs, ":"); - std::copy(additional_libs_vector.begin(), additional_libs_vector.end(), - std::back_inserter(sonames)); - // Apply the same list to the runtime namespace, since some libraries - // might reside there. - CHECK(sizeof(kRuntimePublicLibraries) > 0); - runtime_public_libraries = runtime_public_libraries + ':' + additional_libs; - } - } - - // Remove the public libs in the runtime namespace. - // These libs are listed in public.android.txt, but we don't want the rest of android - // in default namespace to dlopen the libs. - // For example, libicuuc.so is exposed to classloader namespace from runtime namespace. - // Unfortunately, it does not have stable C symbols, and default namespace should only use - // stable symbols in libandroidicu.so. http://b/120786417 - removePublicLibsIfExistsInRuntimeApex(sonames); - // android_init_namespaces() expects all the public libraries // to be loaded so that they can be found by soname alone. // @@ -327,44 +127,10 @@ void LibraryNamespaces::Initialize() { // we might as well end up loading them from /system/lib or /product/lib // For now we rely on CTS test to catch things like this but // it should probably be addressed in the future. - for (const auto& soname : sonames) { + for (const auto& soname : android::base::Split(system_public_libraries(), ":")) { LOG_ALWAYS_FATAL_IF(dlopen(soname.c_str(), RTLD_NOW | RTLD_NODELETE) == nullptr, "Error preloading public library %s: %s", soname.c_str(), dlerror()); } - - system_public_libraries_ = base::Join(sonames, ':'); - runtime_public_libraries_ = runtime_public_libraries; - - // read /system/etc/public.libraries-.txt which contain partner defined - // system libs that are exposed to apps. The libs in the txt files must be - // named as lib..so. - sonames.clear(); - ReadExtensionLibraries(base::Dirname(public_native_libraries_system_config).c_str(), &sonames); - oem_public_libraries_ = base::Join(sonames, ':'); - - // read /product/etc/public.libraries-.txt which contain partner defined - // product libs that are exposed to apps. - sonames.clear(); - ReadExtensionLibraries(product_public_native_libraries_dir.c_str(), &sonames); - product_public_libraries_ = base::Join(sonames, ':'); - - // Insert VNDK version to llndk and vndksp config file names. - insert_vndk_version_str(&llndk_native_libraries_system_config); - insert_vndk_version_str(&vndksp_native_libraries_system_config); - - sonames.clear(); - ReadConfig(llndk_native_libraries_system_config, &sonames, always_true); - system_llndk_libraries_ = base::Join(sonames, ':'); - - sonames.clear(); - ReadConfig(vndksp_native_libraries_system_config, &sonames, always_true); - system_vndksp_libraries_ = base::Join(sonames, ':'); - - sonames.clear(); - // This file is optional, quietly ignore if the file does not exist. - ReadConfig(kPublicNativeLibrariesVendorConfig, &sonames, always_true, nullptr); - - vendor_public_libraries_ = base::Join(sonames, ':'); } NativeLoaderNamespace* LibraryNamespaces::Create(JNIEnv* env, uint32_t target_sdk_version, @@ -425,7 +191,7 @@ NativeLoaderNamespace* LibraryNamespaces::Create(JNIEnv* env, uint32_t target_sd is_native_bridge = NativeBridgeIsPathSupported(library_path.c_str()); } - std::string system_exposed_libraries = system_public_libraries_; + std::string system_exposed_libraries = system_public_libraries(); const char* namespace_name = kClassloaderNamespaceName; android_namespace_t* vndk_ns = nullptr; if ((apk_origin == APK_ORIGIN_VENDOR || @@ -461,7 +227,7 @@ NativeLoaderNamespace* LibraryNamespaces::Create(JNIEnv* env, uint32_t target_sd permitted_path = permitted_path + ":" + origin_lib_path; // Also give access to LLNDK libraries since they are available to vendors - system_exposed_libraries = system_exposed_libraries + ":" + system_llndk_libraries_.c_str(); + 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); @@ -476,14 +242,14 @@ NativeLoaderNamespace* LibraryNamespaces::Create(JNIEnv* env, uint32_t target_sd } else { // oem and product public libraries are NOT available to vendor apks, otherwise it // would be system->vendor violation. - if (!oem_public_libraries_.empty()) { - system_exposed_libraries = system_exposed_libraries + ':' + oem_public_libraries_; + if (!oem_public_libraries().empty()) { + system_exposed_libraries = system_exposed_libraries + ':' + oem_public_libraries(); } - if (!product_public_libraries_.empty()) { - system_exposed_libraries = system_exposed_libraries + ':' + product_public_libraries_; + if (!product_public_libraries().empty()) { + system_exposed_libraries = system_exposed_libraries + ':' + product_public_libraries(); } } - std::string runtime_exposed_libraries = runtime_public_libraries_; + std::string runtime_exposed_libraries = runtime_public_libraries(); NativeLoaderNamespace native_loader_ns; if (!is_native_bridge) { @@ -531,16 +297,16 @@ NativeLoaderNamespace* LibraryNamespaces::Create(JNIEnv* env, uint32_t target_sd } } - if (vndk_ns != nullptr && !system_vndksp_libraries_.empty()) { + 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())) { + if (!android_link_namespaces(ns, vndk_ns, system_vndksp_libraries().c_str())) { *error_msg = dlerror(); return nullptr; } } - if (!vendor_public_libraries_.empty()) { - if (!android_link_namespaces(ns, vendor_ns, vendor_public_libraries_.c_str())) { + if (!vendor_public_libraries().empty()) { + if (!android_link_namespaces(ns, vendor_ns, vendor_public_libraries().c_str())) { *error_msg = dlerror(); return nullptr; } @@ -586,8 +352,8 @@ NativeLoaderNamespace* LibraryNamespaces::Create(JNIEnv* env, uint32_t target_sd return nullptr; } } - if (!vendor_public_libraries_.empty()) { - if (!NativeBridgeLinkNamespaces(ns, vendor_ns, vendor_public_libraries_.c_str())) { + if (!vendor_public_libraries().empty()) { + if (!NativeBridgeLinkNamespaces(ns, vendor_ns, vendor_public_libraries().c_str())) { *error_msg = NativeBridgeGetError(); return nullptr; } @@ -622,7 +388,7 @@ bool LibraryNamespaces::InitPublicNamespace(const char* library_path, std::strin // code is one example) unknown to linker in which case linker uses anonymous // namespace. The second argument specifies the search path for the anonymous // namespace which is the library_path of the classloader. - initialized_ = android_init_anonymous_namespace(system_public_libraries_.c_str(), + initialized_ = android_init_anonymous_namespace(system_public_libraries().c_str(), is_native_bridge ? nullptr : library_path); if (!initialized_) { *error_msg = dlerror(); @@ -631,7 +397,7 @@ bool LibraryNamespaces::InitPublicNamespace(const char* library_path, std::strin // and now initialize native bridge namespaces if necessary. if (NativeBridgeInitialized()) { - initialized_ = NativeBridgeInitAnonymousNamespace(system_public_libraries_.c_str(), + initialized_ = NativeBridgeInitAnonymousNamespace(system_public_libraries().c_str(), is_native_bridge ? library_path : nullptr); if (!initialized_) { *error_msg = NativeBridgeGetError(); @@ -657,4 +423,4 @@ NativeLoaderNamespace* LibraryNamespaces::FindParentNamespaceByClassLoader(JNIEn return nullptr; } -} // namespace android +} // namespace android::nativeloader diff --git a/libnativeloader/library_namespaces.h b/libnativeloader/library_namespaces.h index 353b5fcf0..ff8fda983 100644 --- a/libnativeloader/library_namespaces.h +++ b/libnativeloader/library_namespaces.h @@ -18,6 +18,8 @@ #error "Not available for host" #endif +#define LOG_TAG "nativeloader" + #include "native_loader_namespace.h" #include @@ -25,7 +27,7 @@ #include "jni.h" -namespace android { +namespace android::nativeloader { // LibraryNamespaces is a singleton object that manages NativeLoaderNamespace // objects for an app process. Its main job is to create (and configure) a new @@ -52,13 +54,6 @@ class LibraryNamespaces { bool initialized_; std::list> namespaces_; - std::string system_public_libraries_; - std::string runtime_public_libraries_; - std::string vendor_public_libraries_; - std::string oem_public_libraries_; - std::string product_public_libraries_; - std::string system_llndk_libraries_; - std::string system_vndksp_libraries_; }; -} // namespace android +} // namespace android::nativeloader diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp index ed98714ff..eeee077df 100644 --- a/libnativeloader/native_loader.cpp +++ b/libnativeloader/native_loader.cpp @@ -40,6 +40,8 @@ namespace android { namespace { #if defined(__ANDROID__) +using android::nativeloader::LibraryNamespaces; + constexpr const char* kApexPath = "/apex/"; std::mutex g_namespaces_mutex; diff --git a/libnativeloader/public_libraries.cpp b/libnativeloader/public_libraries.cpp new file mode 100644 index 000000000..8e3f9e811 --- /dev/null +++ b/libnativeloader/public_libraries.cpp @@ -0,0 +1,322 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "public_libraries.h" +#define LOG_TAG "nativeloader" + +#include + +#include +#include + +#include "android-base/file.h" +#include "android-base/logging.h" +#include "android-base/properties.h" +#include "android-base/strings.h" +#include "log/log.h" + +namespace android::nativeloader { + +using namespace std::string_literals; + +namespace { +// TODO(b/130388701) simplify the names below +constexpr const char kPublicNativeLibrariesSystemConfigPathFromRoot[] = "/etc/public.libraries.txt"; +constexpr const char kPublicNativeLibrariesExtensionConfigPrefix[] = "public.libraries-"; +constexpr const size_t kPublicNativeLibrariesExtensionConfigPrefixLen = + sizeof(kPublicNativeLibrariesExtensionConfigPrefix) - 1; +constexpr const char kPublicNativeLibrariesExtensionConfigSuffix[] = ".txt"; +constexpr const size_t kPublicNativeLibrariesExtensionConfigSuffixLen = + sizeof(kPublicNativeLibrariesExtensionConfigSuffix) - 1; +constexpr const char kPublicNativeLibrariesVendorConfig[] = "/vendor/etc/public.libraries.txt"; +constexpr const char kLlndkNativeLibrariesSystemConfigPathFromRoot[] = "/etc/llndk.libraries.txt"; +constexpr const char kVndkspNativeLibrariesSystemConfigPathFromRoot[] = "/etc/vndksp.libraries.txt"; + +const std::vector kRuntimePublicLibraries = { + "libicuuc.so", + "libicui18n.so", +}; + +// TODO(b/130388701) use macro LIB to eliminate the conditional +#if defined(__LP64__) +constexpr const char* kRuntimeApexLibPath = "/apex/com.android.runtime/lib64"; +#else +constexpr const char* kRuntimeApexLibPath = "/apex/com.android.runtime/lib"; +#endif + +std::string root_dir() { + static const char* android_root_env = getenv("ANDROID_ROOT"); + return android_root_env != nullptr ? android_root_env : "/system"; +} + +bool debuggable() { + bool debuggable = false; + debuggable = android::base::GetBoolProperty("ro.debuggable", false); + return debuggable; +} + +std::string vndk_version_str() { + std::string version = android::base::GetProperty("ro.vndk.version", ""); + if (version != "" && version != "current") { + return "." + version; + } + return ""; +} + +void insert_vndk_version_str(std::string* file_name) { + CHECK(file_name != nullptr); + size_t insert_pos = file_name->find_last_of("."); + if (insert_pos == std::string::npos) { + insert_pos = file_name->length(); + } + file_name->insert(insert_pos, vndk_version_str()); +} + +const std::function always_true = + [](const std::string&, std::string*) { return true; }; + +bool ReadConfig(const std::string& configFile, std::vector* sonames, + const std::function& check_soname, + std::string* error_msg = nullptr) { + // Read list of public native libraries from the config file. + std::string file_content; + if (!base::ReadFileToString(configFile, &file_content)) { + if (error_msg) *error_msg = strerror(errno); + return false; + } + + std::vector lines = base::Split(file_content, "\n"); + + for (auto& line : lines) { + auto trimmed_line = base::Trim(line); + if (trimmed_line[0] == '#' || trimmed_line.empty()) { + continue; + } + size_t space_pos = trimmed_line.rfind(' '); + if (space_pos != std::string::npos) { + std::string type = trimmed_line.substr(space_pos + 1); + if (type != "32" && type != "64") { + if (error_msg) *error_msg = "Malformed line: " + line; + return false; + } +#if defined(__LP64__) + // Skip 32 bit public library. + if (type == "32") { + continue; + } +#else + // Skip 64 bit public library. + if (type == "64") { + continue; + } +#endif + trimmed_line.resize(space_pos); + } + + if (check_soname(trimmed_line, error_msg)) { + sonames->push_back(trimmed_line); + } else { + return false; + } + } + return true; +} + +void ReadExtensionLibraries(const char* dirname, std::vector* sonames) { + std::unique_ptr dir(opendir(dirname), closedir); + if (dir != nullptr) { + // Failing to opening the dir is not an error, which can happen in + // webview_zygote. + while (struct dirent* ent = readdir(dir.get())) { + if (ent->d_type != DT_REG && ent->d_type != DT_LNK) { + continue; + } + const std::string filename(ent->d_name); + if (android::base::StartsWith(filename, kPublicNativeLibrariesExtensionConfigPrefix) && + android::base::EndsWith(filename, kPublicNativeLibrariesExtensionConfigSuffix)) { + const size_t start = kPublicNativeLibrariesExtensionConfigPrefixLen; + const size_t end = filename.size() - kPublicNativeLibrariesExtensionConfigSuffixLen; + const std::string company_name = filename.substr(start, end - start); + const std::string config_file_path = dirname + "/"s + filename; + LOG_ALWAYS_FATAL_IF( + company_name.empty(), + "Error extracting company name from public native library list file path \"%s\"", + config_file_path.c_str()); + + std::string error_msg; + + LOG_ALWAYS_FATAL_IF( + !ReadConfig(config_file_path, sonames, + [&company_name](const std::string& soname, std::string* error_msg) { + if (android::base::StartsWith(soname, "lib") && + android::base::EndsWith(soname, "." + company_name + ".so")) { + return true; + } else { + *error_msg = "Library name \"" + soname + + "\" does not end with the company name: " + company_name + + "."; + return false; + } + }, + &error_msg), + "Error reading public native library list from \"%s\": %s", config_file_path.c_str(), + error_msg.c_str()); + } + } + } +} + +} // namespace + +const std::string& system_public_libraries() { + static bool cached = false; + static std::string list; + if (!cached) { + std::string config_file = root_dir() + kPublicNativeLibrariesSystemConfigPathFromRoot; + std::vector sonames; + std::string error_msg; + LOG_ALWAYS_FATAL_IF(!ReadConfig(config_file, &sonames, always_true, &error_msg), + "Error reading public native library list from \"%s\": %s", + config_file.c_str(), error_msg.c_str()); + + // For debuggable platform builds use ANDROID_ADDITIONAL_PUBLIC_LIBRARIES environment + // variable to add libraries to the list. This is intended for platform tests only. + if (debuggable()) { + const char* additional_libs = getenv("ANDROID_ADDITIONAL_PUBLIC_LIBRARIES"); + if (additional_libs != nullptr && additional_libs[0] != '\0') { + std::vector additional_libs_vector = base::Split(additional_libs, ":"); + std::copy(additional_libs_vector.begin(), additional_libs_vector.end(), + std::back_inserter(sonames)); + } + } + + // Remove the public libs in the runtime namespace. + // These libs are listed in public.android.txt, but we don't want the rest of android + // in default namespace to dlopen the libs. + // For example, libicuuc.so is exposed to classloader namespace from runtime namespace. + // Unfortunately, it does not have stable C symbols, and default namespace should only use + // stable symbols in libandroidicu.so. http://b/120786417 + for (const std::string& lib_name : kRuntimePublicLibraries) { + std::string path(kRuntimeApexLibPath); + path.append("/").append(lib_name); + + struct stat s; + // Do nothing if the path in /apex does not exist. + // Runtime APEX must be mounted since libnativeloader is in the same APEX + if (stat(path.c_str(), &s) != 0) { + continue; + } + + auto it = std::find(sonames.begin(), sonames.end(), lib_name); + if (it != sonames.end()) { + sonames.erase(it); + } + } + list = android::base::Join(sonames, ':'); + cached = true; + } + return list; +} + +const std::string& runtime_public_libraries() { + static bool cached = false; + static std::string list; + if (!cached) { + list = android::base::Join(kRuntimePublicLibraries, ":"); + // For debuggable platform builds use ANDROID_ADDITIONAL_PUBLIC_LIBRARIES environment + // variable to add libraries to the list. This is intended for platform tests only. + if (debuggable()) { + const char* additional_libs = getenv("ANDROID_ADDITIONAL_PUBLIC_LIBRARIES"); + if (additional_libs != nullptr && additional_libs[0] != '\0') { + list = list + ':' + additional_libs; + } + } + } + return list; +} + +const std::string& vendor_public_libraries() { + static bool cached = false; + static std::string list; + if (!cached) { + // This file is optional, quietly ignore if the file does not exist. + std::vector sonames; + ReadConfig(kPublicNativeLibrariesVendorConfig, &sonames, always_true, nullptr); + list = android::base::Join(sonames, ':'); + cached = true; + } + return list; +} + +// read /system/etc/public.libraries-.txt which contain partner defined +// system libs that are exposed to apps. The libs in the txt files must be +// named as lib..so. +const std::string& oem_public_libraries() { + static bool cached = false; + static std::string list; + if (!cached) { + std::vector sonames; + ReadExtensionLibraries("/system/etc", &sonames); + list = android::base::Join(sonames, ':'); + cached = true; + } + return list; +} + +// read /product/etc/public.libraries-.txt which contain partner defined +// product libs that are exposed to apps. +const std::string& product_public_libraries() { + static bool cached = false; + static std::string list; + if (!cached) { + std::vector sonames; + ReadExtensionLibraries("/product/etc", &sonames); + list = android::base::Join(sonames, ':'); + cached = true; + } + return list; +} + +const std::string& system_llndk_libraries() { + static bool cached = false; + static std::string list; + if (!cached) { + std::string config_file = root_dir() + kLlndkNativeLibrariesSystemConfigPathFromRoot; + insert_vndk_version_str(&config_file); + std::vector sonames; + ReadConfig(config_file, &sonames, always_true, nullptr); + list = android::base::Join(sonames, ':'); + cached = true; + } + return list; +} + +const std::string& system_vndksp_libraries() { + static bool cached = false; + static std::string list; + if (!cached) { + std::string config_file = root_dir() + kVndkspNativeLibrariesSystemConfigPathFromRoot; + insert_vndk_version_str(&config_file); + std::vector sonames; + ReadConfig(config_file, &sonames, always_true, nullptr); + list = android::base::Join(sonames, ':'); + cached = true; + } + return list; +} + +} // namespace android::nativeloader diff --git a/libnativeloader/public_libraries.h b/libnativeloader/public_libraries.h new file mode 100644 index 000000000..a21190701 --- /dev/null +++ b/libnativeloader/public_libraries.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include + +namespace android::nativeloader { + +// These provide the list of libraries that are available to the namespace for apps. +// Not all of the libraries are available to apps. Depending on the context, +// e.g., if it is a vendor app or not, different set of libraries are made available. +// TODO(b/130388701) rename these. +const std::string& system_public_libraries(); +const std::string& runtime_public_libraries(); +const std::string& vendor_public_libraries(); +const std::string& oem_public_libraries(); +const std::string& product_public_libraries(); +const std::string& system_llndk_libraries(); +const std::string& system_vndksp_libraries(); + +}; // namespace android::nativeloader From f8802e5f0a74caf51897b7dd51412ae7d04d0fe8 Mon Sep 17 00:00:00 2001 From: Jiyong Park Date: Fri, 3 May 2019 16:34:56 +0900 Subject: [PATCH 2/3] Introduce utils.h Introduce utils.h to have common routines. Bug: 130388701 Test: build & pass presubmit tests Change-Id: Ic40da64fefc1f2216bdea9ea93a15e5abb8f23a4 --- libnativeloader/library_namespaces.cpp | 11 +++------- libnativeloader/library_namespaces.h | 1 + libnativeloader/native_loader_namespace.h | 1 + libnativeloader/public_libraries.cpp | 8 ++----- libnativeloader/utils.h | 26 +++++++++++++++++++++++ 5 files changed, 33 insertions(+), 14 deletions(-) create mode 100644 libnativeloader/utils.h diff --git a/libnativeloader/library_namespaces.cpp b/libnativeloader/library_namespaces.cpp index b80e9a1b6..0441bbbb9 100644 --- a/libnativeloader/library_namespaces.cpp +++ b/libnativeloader/library_namespaces.cpp @@ -30,6 +30,7 @@ #include "nativehelper/ScopedUtfChars.h" #include "nativeloader/dlext_namespaces.h" #include "public_libraries.h" +#include "utils.h" namespace android::nativeloader { @@ -61,14 +62,8 @@ constexpr const char* kVendorClassloaderNamespaceName = "vendor-classloader-name // This list includes all directories app is allowed to access this way. constexpr const char* kWhitelistedDirectories = "/data:/mnt/expand"; -// TODO(b/130388701) use macro LIB to eliminate the conditional -#if defined(__LP64__) -constexpr const char* kVendorLibPath = "/vendor/lib64"; -constexpr const char* kProductLibPath = "/product/lib64:/system/product/lib64"; -#else -constexpr const char* kVendorLibPath = "/vendor/lib"; -constexpr const char* kProductLibPath = "/product/lib:/system/product/lib"; -#endif +constexpr const char* kVendorLibPath = "/vendor/" LIB; +constexpr const char* kProductLibPath = "/product/" LIB ":/system/product/" LIB; const std::regex kVendorDexPathRegex("(^|:)/vendor/"); const std::regex kProductDexPathRegex("(^|:)(/system)?/product/"); diff --git a/libnativeloader/library_namespaces.h b/libnativeloader/library_namespaces.h index ff8fda983..103cfacbc 100644 --- a/libnativeloader/library_namespaces.h +++ b/libnativeloader/library_namespaces.h @@ -26,6 +26,7 @@ #include #include "jni.h" +#include "utils.h" namespace android::nativeloader { diff --git a/libnativeloader/native_loader_namespace.h b/libnativeloader/native_loader_namespace.h index 71b60d833..b983a2ddb 100644 --- a/libnativeloader/native_loader_namespace.h +++ b/libnativeloader/native_loader_namespace.h @@ -22,6 +22,7 @@ #include "android/dlext.h" #include "log/log.h" #include "nativebridge/native_bridge.h" +#include "utils.h" namespace android { diff --git a/libnativeloader/public_libraries.cpp b/libnativeloader/public_libraries.cpp index 8e3f9e811..e6f8448e5 100644 --- a/libnativeloader/public_libraries.cpp +++ b/libnativeloader/public_libraries.cpp @@ -27,6 +27,7 @@ #include "android-base/properties.h" #include "android-base/strings.h" #include "log/log.h" +#include "utils.h" namespace android::nativeloader { @@ -50,12 +51,7 @@ const std::vector kRuntimePublicLibraries = { "libicui18n.so", }; -// TODO(b/130388701) use macro LIB to eliminate the conditional -#if defined(__LP64__) -constexpr const char* kRuntimeApexLibPath = "/apex/com.android.runtime/lib64"; -#else -constexpr const char* kRuntimeApexLibPath = "/apex/com.android.runtime/lib"; -#endif +constexpr const char* kRuntimeApexLibPath = "/apex/com.android.runtime/" LIB; std::string root_dir() { static const char* android_root_env = getenv("ANDROID_ROOT"); diff --git a/libnativeloader/utils.h b/libnativeloader/utils.h new file mode 100644 index 000000000..a1c2be547 --- /dev/null +++ b/libnativeloader/utils.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +namespace android::nativeloader { + +#if defined(__LP64__) +#define LIB "lib64" +#else +#define LIB "lib" +#endif + +} // namespace android::nativeloader From 5b8b306b42363a9c35a3e198bd8cf26f4c24844c Mon Sep 17 00:00:00 2001 From: Jiyong Park Date: Fri, 3 May 2019 18:11:49 +0900 Subject: [PATCH 3/3] Refactor public_libraries.* - shorten the long const variables - merge {oem|product}_public_libraries into extended_public_libraries Bug: 130388701 Test: build & pass presubmit tests Change-Id: I43be555041466118f2b2d188f5da3ff0d8ed7d8d --- libnativeloader/library_namespaces.cpp | 23 ++++----- libnativeloader/public_libraries.cpp | 71 ++++++++++---------------- libnativeloader/public_libraries.h | 10 ++-- 3 files changed, 41 insertions(+), 63 deletions(-) diff --git a/libnativeloader/library_namespaces.cpp b/libnativeloader/library_namespaces.cpp index 0441bbbb9..3839a15fa 100644 --- a/libnativeloader/library_namespaces.cpp +++ b/libnativeloader/library_namespaces.cpp @@ -122,7 +122,7 @@ void LibraryNamespaces::Initialize() { // we might as well end up loading them from /system/lib or /product/lib // For now we rely on CTS test to catch things like this but // it should probably be addressed in the future. - for (const auto& soname : android::base::Split(system_public_libraries(), ":")) { + for (const auto& soname : android::base::Split(default_public_libraries(), ":")) { LOG_ALWAYS_FATAL_IF(dlopen(soname.c_str(), RTLD_NOW | RTLD_NODELETE) == nullptr, "Error preloading public library %s: %s", soname.c_str(), dlerror()); } @@ -186,7 +186,7 @@ NativeLoaderNamespace* LibraryNamespaces::Create(JNIEnv* env, uint32_t target_sd is_native_bridge = NativeBridgeIsPathSupported(library_path.c_str()); } - std::string system_exposed_libraries = system_public_libraries(); + std::string system_exposed_libraries = default_public_libraries(); const char* namespace_name = kClassloaderNamespaceName; android_namespace_t* vndk_ns = nullptr; if ((apk_origin == APK_ORIGIN_VENDOR || @@ -222,7 +222,7 @@ NativeLoaderNamespace* LibraryNamespaces::Create(JNIEnv* env, uint32_t target_sd permitted_path = permitted_path + ":" + origin_lib_path; // Also give access to LLNDK libraries since they are available to vendors - system_exposed_libraries = system_exposed_libraries + ":" + system_llndk_libraries().c_str(); + system_exposed_libraries = system_exposed_libraries + ":" + llndk_libraries().c_str(); // Give access to VNDK-SP libraries from the 'vndk' namespace. vndk_ns = android_get_exported_namespace(kVndkNamespaceName); @@ -235,13 +235,10 @@ NativeLoaderNamespace* LibraryNamespaces::Create(JNIEnv* env, uint32_t target_sd ALOGD("classloader namespace configured for unbundled %s apk. library_path=%s", origin_partition, library_path.c_str()); } else { - // oem and product public libraries are NOT available to vendor apks, otherwise it + // extended public libraries are NOT available to vendor apks, otherwise it // would be system->vendor violation. - if (!oem_public_libraries().empty()) { - system_exposed_libraries = system_exposed_libraries + ':' + oem_public_libraries(); - } - if (!product_public_libraries().empty()) { - system_exposed_libraries = system_exposed_libraries + ':' + product_public_libraries(); + if (!extended_public_libraries().empty()) { + system_exposed_libraries = system_exposed_libraries + ':' + extended_public_libraries(); } } std::string runtime_exposed_libraries = runtime_public_libraries(); @@ -292,9 +289,9 @@ NativeLoaderNamespace* LibraryNamespaces::Create(JNIEnv* env, uint32_t target_sd } } - if (vndk_ns != nullptr && !system_vndksp_libraries().empty()) { + if (vndk_ns != nullptr && !vndksp_libraries().empty()) { // vendor apks are allowed to use VNDK-SP libraries. - if (!android_link_namespaces(ns, vndk_ns, system_vndksp_libraries().c_str())) { + if (!android_link_namespaces(ns, vndk_ns, vndksp_libraries().c_str())) { *error_msg = dlerror(); return nullptr; } @@ -383,7 +380,7 @@ bool LibraryNamespaces::InitPublicNamespace(const char* library_path, std::strin // code is one example) unknown to linker in which case linker uses anonymous // namespace. The second argument specifies the search path for the anonymous // namespace which is the library_path of the classloader. - initialized_ = android_init_anonymous_namespace(system_public_libraries().c_str(), + initialized_ = android_init_anonymous_namespace(default_public_libraries().c_str(), is_native_bridge ? nullptr : library_path); if (!initialized_) { *error_msg = dlerror(); @@ -392,7 +389,7 @@ bool LibraryNamespaces::InitPublicNamespace(const char* library_path, std::strin // and now initialize native bridge namespaces if necessary. if (NativeBridgeInitialized()) { - initialized_ = NativeBridgeInitAnonymousNamespace(system_public_libraries().c_str(), + initialized_ = NativeBridgeInitAnonymousNamespace(default_public_libraries().c_str(), is_native_bridge ? library_path : nullptr); if (!initialized_) { *error_msg = NativeBridgeGetError(); diff --git a/libnativeloader/public_libraries.cpp b/libnativeloader/public_libraries.cpp index e6f8448e5..c473f2cab 100644 --- a/libnativeloader/public_libraries.cpp +++ b/libnativeloader/public_libraries.cpp @@ -34,17 +34,13 @@ namespace android::nativeloader { using namespace std::string_literals; namespace { -// TODO(b/130388701) simplify the names below -constexpr const char kPublicNativeLibrariesSystemConfigPathFromRoot[] = "/etc/public.libraries.txt"; -constexpr const char kPublicNativeLibrariesExtensionConfigPrefix[] = "public.libraries-"; -constexpr const size_t kPublicNativeLibrariesExtensionConfigPrefixLen = - sizeof(kPublicNativeLibrariesExtensionConfigPrefix) - 1; -constexpr const char kPublicNativeLibrariesExtensionConfigSuffix[] = ".txt"; -constexpr const size_t kPublicNativeLibrariesExtensionConfigSuffixLen = - sizeof(kPublicNativeLibrariesExtensionConfigSuffix) - 1; -constexpr const char kPublicNativeLibrariesVendorConfig[] = "/vendor/etc/public.libraries.txt"; -constexpr const char kLlndkNativeLibrariesSystemConfigPathFromRoot[] = "/etc/llndk.libraries.txt"; -constexpr const char kVndkspNativeLibrariesSystemConfigPathFromRoot[] = "/etc/vndksp.libraries.txt"; + +constexpr const char* kDefaultPublicLibrariesFile = "/etc/public.libraries.txt"; +constexpr const char* kExtendedPublicLibrariesFilePrefix = "public.libraries-"; +constexpr const char* kExtendedPublicLibrariesFileSuffix = ".txt"; +constexpr const char* kVendorPublicLibrariesFile = "/vendor/etc/public.libraries.txt"; +constexpr const char* kLlndkLibrariesFile = "/system/etc/llndk.libraries.txt"; +constexpr const char* kVndkLibrariesFile = "/system/etc/vndksp.libraries.txt"; const std::vector kRuntimePublicLibraries = { "libicuuc.so", @@ -53,26 +49,26 @@ const std::vector kRuntimePublicLibraries = { constexpr const char* kRuntimeApexLibPath = "/apex/com.android.runtime/" LIB; +// TODO(b/130388701): do we need this? std::string root_dir() { static const char* android_root_env = getenv("ANDROID_ROOT"); return android_root_env != nullptr ? android_root_env : "/system"; } bool debuggable() { - bool debuggable = false; - debuggable = android::base::GetBoolProperty("ro.debuggable", false); + static bool debuggable = android::base::GetBoolProperty("ro.debuggable", false); return debuggable; } std::string vndk_version_str() { - std::string version = android::base::GetProperty("ro.vndk.version", ""); + static std::string version = android::base::GetProperty("ro.vndk.version", ""); if (version != "" && version != "current") { return "." + version; } return ""; } -void insert_vndk_version_str(std::string* file_name) { +void InsertVndkVersionStr(std::string* file_name) { CHECK(file_name != nullptr); size_t insert_pos = file_name->find_last_of("."); if (insert_pos == std::string::npos) { @@ -142,11 +138,10 @@ void ReadExtensionLibraries(const char* dirname, std::vector* sonam continue; } const std::string filename(ent->d_name); - if (android::base::StartsWith(filename, kPublicNativeLibrariesExtensionConfigPrefix) && - android::base::EndsWith(filename, kPublicNativeLibrariesExtensionConfigSuffix)) { - const size_t start = kPublicNativeLibrariesExtensionConfigPrefixLen; - const size_t end = filename.size() - kPublicNativeLibrariesExtensionConfigSuffixLen; - const std::string company_name = filename.substr(start, end - start); + std::string_view fn = filename; + if (android::base::ConsumePrefix(&fn, kExtendedPublicLibrariesFilePrefix) && + android::base::ConsumeSuffix(&fn, kExtendedPublicLibrariesFileSuffix)) { + const std::string company_name(fn); const std::string config_file_path = dirname + "/"s + filename; LOG_ALWAYS_FATAL_IF( company_name.empty(), @@ -178,11 +173,11 @@ void ReadExtensionLibraries(const char* dirname, std::vector* sonam } // namespace -const std::string& system_public_libraries() { +const std::string& default_public_libraries() { static bool cached = false; static std::string list; if (!cached) { - std::string config_file = root_dir() + kPublicNativeLibrariesSystemConfigPathFromRoot; + std::string config_file = root_dir() + kDefaultPublicLibrariesFile; std::vector sonames; std::string error_msg; LOG_ALWAYS_FATAL_IF(!ReadConfig(config_file, &sonames, always_true, &error_msg), @@ -251,35 +246,23 @@ const std::string& vendor_public_libraries() { if (!cached) { // This file is optional, quietly ignore if the file does not exist. std::vector sonames; - ReadConfig(kPublicNativeLibrariesVendorConfig, &sonames, always_true, nullptr); + ReadConfig(kVendorPublicLibrariesFile, &sonames, always_true, nullptr); list = android::base::Join(sonames, ':'); cached = true; } return list; } -// read /system/etc/public.libraries-.txt which contain partner defined +// read /system/etc/public.libraries-.txt and +// /product/etc/public.libraries-.txt which contain partner defined // system libs that are exposed to apps. The libs in the txt files must be // named as lib..so. -const std::string& oem_public_libraries() { +const std::string& extended_public_libraries() { static bool cached = false; static std::string list; if (!cached) { std::vector sonames; ReadExtensionLibraries("/system/etc", &sonames); - list = android::base::Join(sonames, ':'); - cached = true; - } - return list; -} - -// read /product/etc/public.libraries-.txt which contain partner defined -// product libs that are exposed to apps. -const std::string& product_public_libraries() { - static bool cached = false; - static std::string list; - if (!cached) { - std::vector sonames; ReadExtensionLibraries("/product/etc", &sonames); list = android::base::Join(sonames, ':'); cached = true; @@ -287,12 +270,12 @@ const std::string& product_public_libraries() { return list; } -const std::string& system_llndk_libraries() { +const std::string& llndk_libraries() { static bool cached = false; static std::string list; if (!cached) { - std::string config_file = root_dir() + kLlndkNativeLibrariesSystemConfigPathFromRoot; - insert_vndk_version_str(&config_file); + std::string config_file = kLlndkLibrariesFile; + InsertVndkVersionStr(&config_file); std::vector sonames; ReadConfig(config_file, &sonames, always_true, nullptr); list = android::base::Join(sonames, ':'); @@ -301,12 +284,12 @@ const std::string& system_llndk_libraries() { return list; } -const std::string& system_vndksp_libraries() { +const std::string& vndksp_libraries() { static bool cached = false; static std::string list; if (!cached) { - std::string config_file = root_dir() + kVndkspNativeLibrariesSystemConfigPathFromRoot; - insert_vndk_version_str(&config_file); + std::string config_file = kVndkLibrariesFile; + InsertVndkVersionStr(&config_file); std::vector sonames; ReadConfig(config_file, &sonames, always_true, nullptr); list = android::base::Join(sonames, ':'); diff --git a/libnativeloader/public_libraries.h b/libnativeloader/public_libraries.h index a21190701..9b6dea88a 100644 --- a/libnativeloader/public_libraries.h +++ b/libnativeloader/public_libraries.h @@ -22,13 +22,11 @@ namespace android::nativeloader { // These provide the list of libraries that are available to the namespace for apps. // Not all of the libraries are available to apps. Depending on the context, // e.g., if it is a vendor app or not, different set of libraries are made available. -// TODO(b/130388701) rename these. -const std::string& system_public_libraries(); +const std::string& default_public_libraries(); const std::string& runtime_public_libraries(); const std::string& vendor_public_libraries(); -const std::string& oem_public_libraries(); -const std::string& product_public_libraries(); -const std::string& system_llndk_libraries(); -const std::string& system_vndksp_libraries(); +const std::string& extended_public_libraries(); +const std::string& llndk_libraries(); +const std::string& vndksp_libraries(); }; // namespace android::nativeloader