Support product-specific libraries

Product-specific libraries in /product/lib can be exposed to Android
apps by adding the list of the libs into
/product/etc/public.libraries-<companyname>.txt. The libs MUST be named
as lib<name>.<companyname>.so.

Bug: 73095206
Test: with taimen
mma -j and runtest.sh. The libs are all loaded in system, but not in
vendor. After reinstalling app using adb -r and reopening app, only
libraries listed in .txt are loaded

Change-Id: I7c386813c72a7b225a7f244b6c5fec4ac0660fd3
This commit is contained in:
Inseob Kim 2018-05-04 11:39:12 +09:00
parent a3d95cf2f8
commit 67cb05654c
7 changed files with 118 additions and 51 deletions

View File

@ -46,6 +46,8 @@
"%s:%d: %s CHECK '" #predicate "' failed.",\
__FILE__, __LINE__, __FUNCTION__)
using namespace std::string_literals;
namespace android {
#if defined(__ANDROID__)
@ -236,10 +238,15 @@ class LibraryNamespaces {
// Different name is useful for debugging
namespace_name = kVendorClassloaderNamespaceName;
ALOGD("classloader namespace configured for unbundled vendor apk. library_path=%s", library_path.c_str());
} else if (!oem_public_libraries_.empty()) {
// oem_public_libraries are NOT available to vendor apks, otherwise it
} else {
// oem and product public libraries are NOT available to vendor apks, otherwise it
// would be system->vendor violation.
system_exposed_libraries = system_exposed_libraries + ":" + oem_public_libraries_.c_str();
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_;
}
}
NativeLoaderNamespace native_loader_ns;
@ -351,6 +358,8 @@ class LibraryNamespaces {
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),
@ -373,7 +382,7 @@ class LibraryNamespaces {
//
// TODO(dimitry): this is a bit misleading since we do not know
// if the vendor public library is going to be opened from /vendor/lib
// we might as well end up loading them from /system/lib
// 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) {
@ -387,48 +396,15 @@ class LibraryNamespaces {
// system libs that are exposed to apps. The libs in the txt files must be
// named as lib<name>.<companyname>.so.
sonames.clear();
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")) {
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());
}
}
}
ReadExtensionLibraries(base::Dirname(public_native_libraries_system_config).c_str(), &sonames);
oem_public_libraries_ = base::Join(sonames, ':');
// read /product/etc/public.libraries-<companyname>.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);
@ -448,11 +424,54 @@ class LibraryNamespaces {
vendor_public_libraries_ = base::Join(sonames, ':');
}
void Reset() {
namespaces_.clear();
}
void Reset() { namespaces_.clear(); }
private:
void ReadExtensionLibraries(const char* dirname, std::vector<std::string>* sonames) {
std::unique_ptr<DIR, decltype(&closedir)> 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());
}
}
}
}
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,
@ -559,6 +578,7 @@ class LibraryNamespaces {
std::string system_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_;

View File

@ -49,3 +49,23 @@ cc_library {
"libbase",
],
}
cc_library {
name: "libfoo.product1",
srcs: ["test.cpp"],
cflags: ["-DLIBNAME=\"libfoo.product1.so\""],
product_specific: true,
shared_libs: [
"libbase",
],
}
cc_library {
name: "libbar.product1",
srcs: ["test.cpp"],
cflags: ["-DLIBNAME=\"libbar.product1.so\""],
product_specific: true,
shared_libs: [
"libbase",
],
}

View File

@ -29,6 +29,13 @@ LOCAL_MODULE_CLASS := ETC
LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
include $(BUILD_PREBUILT)
include $(CLEAR_VARS)
LOCAL_MODULE := public.libraries-product1.txt
LOCAL_SRC_FILES:= $(LOCAL_MODULE)
LOCAL_MODULE_CLASS := ETC
LOCAL_MODULE_PATH := $(TARGET_OUT_PRODUCT_ETC)
include $(BUILD_PREBUILT)
include $(CLEAR_VARS)
LOCAL_PACKAGE_NAME := oemlibrarytest-system
LOCAL_MODULE_TAGS := tests

View File

@ -0,0 +1,2 @@
libfoo.product1.so
libbar.product1.so

View File

@ -29,6 +29,8 @@ public class TestActivity extends Activity {
tryLoadingLib("bar.oem1");
tryLoadingLib("foo.oem2");
tryLoadingLib("bar.oem2");
tryLoadingLib("foo.product1");
tryLoadingLib("bar.product1");
}
private void tryLoadingLib(String name) {

View File

@ -37,7 +37,8 @@ additional.namespaces = sphal,vndk,rs
###############################################################################
namespace.default.isolated = true
namespace.default.search.paths = /system/${LIB}
namespace.default.search.paths = /system/${LIB}
namespace.default.search.paths += /product/${LIB}
# We can't have entire /system/${LIB} as permitted paths because doing so
# makes it possible to load libs in /system/${LIB}/vndk* directories by
@ -49,6 +50,7 @@ namespace.default.search.paths = /system/${LIB}
namespace.default.permitted.paths = /system/${LIB}/drm
namespace.default.permitted.paths += /system/${LIB}/extractors
namespace.default.permitted.paths += /system/${LIB}/hw
namespace.default.permitted.paths += /product/${LIB}
# These are where odex files are located. libart has to be able to dlopen the files
namespace.default.permitted.paths += /system/framework
namespace.default.permitted.paths += /system/app
@ -68,6 +70,8 @@ namespace.default.permitted.paths += /mnt/expand
namespace.default.asan.search.paths = /data/asan/system/${LIB}
namespace.default.asan.search.paths += /system/${LIB}
namespace.default.asan.search.paths += /data/asan/product/${LIB}
namespace.default.asan.search.paths += /product/${LIB}
namespace.default.asan.permitted.paths = /data
namespace.default.asan.permitted.paths += /system/${LIB}/drm
@ -83,6 +87,7 @@ namespace.default.asan.permitted.paths += /odm/framework
namespace.default.asan.permitted.paths += /odm/app
namespace.default.asan.permitted.paths += /odm/priv-app
namespace.default.asan.permitted.paths += /oem/app
namespace.default.asan.permitted.paths += /product/${LIB}
namespace.default.asan.permitted.paths += /product/framework
namespace.default.asan.permitted.paths += /product/app
namespace.default.asan.permitted.paths += /product/priv-app
@ -320,10 +325,13 @@ namespace.vndk.link.default.allow_all_shared_libs = true
###############################################################################
namespace.system.isolated = false
namespace.system.search.paths = /system/${LIB}
namespace.system.search.paths = /system/${LIB}
namespace.system.search.paths += /product/${LIB}
namespace.system.asan.search.paths = /data/asan/system/${LIB}
namespace.system.asan.search.paths += /system/${LIB}
namespace.system.asan.search.paths += /data/asan/product/${LIB}
namespace.system.asan.search.paths += /product/${LIB}
###############################################################################
# Namespace config for binaries under /postinstall.
@ -335,4 +343,5 @@ namespace.system.asan.search.paths += /system/${LIB}
###############################################################################
[postinstall]
namespace.default.isolated = false
namespace.default.search.paths = /system/${LIB}
namespace.default.search.paths = /system/${LIB}
namespace.default.search.paths += /product/${LIB}

View File

@ -40,6 +40,7 @@ namespace.default.isolated = false
namespace.default.search.paths = /system/${LIB}
namespace.default.search.paths += /odm/${LIB}
namespace.default.search.paths += /vendor/${LIB}
namespace.default.search.paths += /product/${LIB}
namespace.default.asan.search.paths = /data/asan/system/${LIB}
namespace.default.asan.search.paths += /system/${LIB}
@ -47,6 +48,8 @@ namespace.default.asan.search.paths += /data/asan/odm/${LIB}
namespace.default.asan.search.paths += /odm/${LIB}
namespace.default.asan.search.paths += /data/asan/vendor/${LIB}
namespace.default.asan.search.paths += /vendor/${LIB}
namespace.default.asan.search.paths += /data/asan/product/${LIB}
namespace.default.asan.search.paths += /product/${LIB}
###############################################################################
# "sphal" namespace
@ -205,6 +208,7 @@ namespace.default.search.paths += /vendor/${LIB}/vndk-sp
namespace.default.search.paths += /system/${LIB}/vndk%VNDK_VER%
namespace.default.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
namespace.default.search.paths += /system/${LIB}
namespace.default.search.paths += /product/${LIB}
namespace.default.asan.search.paths = /data/asan/odm/${LIB}
namespace.default.asan.search.paths += /odm/${LIB}
@ -224,6 +228,8 @@ namespace.default.asan.search.paths += /data/asan/system/${LIB}/vndk-sp%VNDK_VER
namespace.default.asan.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
namespace.default.asan.search.paths += /data/asan/system/${LIB}
namespace.default.asan.search.paths += /system/${LIB}
namespace.default.asan.search.paths += /data/asan/product/${LIB}
namespace.default.asan.search.paths += /product/${LIB}
###############################################################################
# Namespace config for binaries under /postinstall.
@ -235,4 +241,5 @@ namespace.default.asan.search.paths += /system/${LIB}
###############################################################################
[postinstall]
namespace.default.isolated = false
namespace.default.search.paths = /system/${LIB}
namespace.default.search.paths = /system/${LIB}
namespace.default.search.paths += /product/${LIB}