diff options
author | Jiyong Park <jiyong@google.com> | 2017-11-08 18:44:09 +0900 |
---|---|---|
committer | Jiyong Park <jiyong@google.com> | 2017-12-19 23:35:09 +0900 |
commit | d1006fe659c2ba8d30494e28f7080beeb1e04eb4 (patch) | |
tree | d748c74f3d1afdbb344799fabd3c68852c4fb3a8 /libnativeloader/native_loader.cpp | |
parent | 32c03800c02b34cbf877708836741b80cc50cb23 (diff) |
Support partners to expose their own system libs to Android apps
Partners (entities other than AOSP) can expose their own system
libraries which are in /system/lib[64] to Android apps. This can be done
by adding the name of the libs into the files
/system/etc/public.libraries-<companyname>.txt.
There can be multiple of the txt files on a device, which is for the
case that multiple partners contributing to the same system image
have their own set of public libraries.
The public libraries MUST be named as lib<name>.<companyname>.so. This
is to prevent accidental exposure of AOSP-defined system private libs.
Note 1:
<companyname> doesn't need to be the same as the value of the sysprop
ro.product.manufacturer or anything that can be part of a file path.
Note 2:
This feature is not for exposing SoC-specific libs to Android apps. That
is already done by /vendor/etc/public.libraries.txt and is only for
libs in /vendor/lib[64].
Bug: 68280171
Test: mm -j under /system/core/libnativeloader/test
cts-tradefed run commandAndExit cts-dev -m CtsJniTestCases -t
android.jni.cts.JniStaticTest#test_linker_namespaces
Change-Id: I7d32ec27c7858e35b96c7c98223cc110acb35b81
Diffstat (limited to 'libnativeloader/native_loader.cpp')
-rw-r--r-- | libnativeloader/native_loader.cpp | 98 |
1 files changed, 80 insertions, 18 deletions
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp index f3c70de6c..8c8d064a2 100644 --- a/libnativeloader/native_loader.cpp +++ b/libnativeloader/native_loader.cpp @@ -24,12 +24,15 @@ #include "cutils/properties.h" #include "log/log.h" #endif +#include <dirent.h> +#include <sys/types.h> #include "nativebridge/native_bridge.h" #include <algorithm> -#include <vector> -#include <string> +#include <memory> #include <mutex> +#include <string> +#include <vector> #include <android-base/file.h> #include <android-base/macros.h> @@ -82,15 +85,20 @@ class NativeLoaderNamespace { native_bridge_namespace_t* native_bridge_ns_; }; -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"; - +static constexpr const char kPublicNativeLibrariesSystemConfigPathFromRoot[] = + "/etc/public.libraries.txt"; +static constexpr const char kPublicNativeLibrariesExtensionConfigPrefix[] = "public.libraries-"; +static constexpr const size_t kPublicNativeLibrariesExtensionConfigPrefixLen = + sizeof(kPublicNativeLibrariesExtensionConfigPrefix) - 1; +static constexpr const char kPublicNativeLibrariesExtensionConfigSuffix[] = ".txt"; +static constexpr const size_t kPublicNativeLibrariesExtensionConfigSuffixLen = + sizeof(kPublicNativeLibrariesExtensionConfigSuffix) - 1; +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 @@ -133,6 +141,9 @@ static void insert_vndk_version_str(std::string* file_name) { file_name->insert(insert_pos, vndk_version_str()); } +static const std::function<bool(const std::string&, std::string*)> always_true = + [](const std::string&, std::string*) { return true; }; + class LibraryNamespaces { public: LibraryNamespaces() : initialized_(false) { } @@ -337,9 +348,54 @@ class LibraryNamespaces { root_dir + kVndkspNativeLibrariesSystemConfigPathFromRoot; std::string error_msg; - LOG_ALWAYS_FATAL_IF(!ReadConfig(public_native_libraries_system_config, &sonames, &error_msg), - "Error reading public native library list from \"%s\": %s", - public_native_libraries_system_config.c_str(), error_msg.c_str()); + 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()); + + // read /system/etc/public.libraries-<companyname>.txt which contain partner defined + // system libs that are exposed to apps. The libs in the txt files must be + // named as lib<name>.<companyname>.so. + std::string dirname = base::Dirname(public_native_libraries_system_config); + std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(dirname.c_str()), closedir); + if (dir != nullptr) { + // Failing to opening the dir is not an error, which can happen in + // webview_zygote. + struct dirent* ent; + while ((ent = readdir(dir.get())) != nullptr) { + 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 + "/" + 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()); + 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").c_str())) { + 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()); + } + } + } // Insert VNDK version to llndk and vndksp config file names. insert_vndk_version_str(&llndk_native_libraries_system_config); @@ -374,16 +430,16 @@ class LibraryNamespaces { system_public_libraries_ = base::Join(sonames, ':'); sonames.clear(); - ReadConfig(llndk_native_libraries_system_config, &sonames); + ReadConfig(llndk_native_libraries_system_config, &sonames, always_true); system_llndk_libraries_ = base::Join(sonames, ':'); sonames.clear(); - ReadConfig(vndksp_native_libraries_system_config, &sonames); + 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); + ReadConfig(kPublicNativeLibrariesVendorConfig, &sonames, always_true, nullptr); vendor_public_libraries_ = base::Join(sonames, ':'); } @@ -394,6 +450,8 @@ class LibraryNamespaces { private: bool ReadConfig(const std::string& configFile, std::vector<std::string>* sonames, + const std::function<bool(const std::string& /* soname */, + std::string* /* error_msg */)>& check_soname, std::string* error_msg = nullptr) { // Read list of public native libraries from the config file. std::string file_content; @@ -430,7 +488,11 @@ class LibraryNamespaces { trimmed_line.resize(space_pos); } - sonames->push_back(trimmed_line); + if (check_soname(trimmed_line, error_msg)) { + sonames->push_back(trimmed_line); + } else { + return false; + } } return true; |