Load vendor public libraries to sphal namespace

Load vendor public libraries to sphal namespace
if it exists - preserve old behavior of loading
these libraries to default namespace if sphal
namespace is not present on the device.

Bug: http://b/37410104
Test: cts-tradefed run singleCommand cts --skip-preconditions -m CtsJniTestCases
      on marlin (with enabled sphal configuration) and on angler where ld.config.txt
      is not present.

Change-Id: Iaa3fa437ba2900acc2e5b9c78039fe1553e4c9dd
This commit is contained in:
Dimitry Ivanov 2017-05-01 15:12:49 -07:00
parent eb9694a2d1
commit af0264bbe9
6 changed files with 76 additions and 19 deletions

View File

@ -161,6 +161,9 @@ bool NativeBridgeLinkNamespaces(native_bridge_namespace_t* from, native_bridge_n
// Use NativeBridgeLoadLibrary() instead in non-namespace scenario.
void* NativeBridgeLoadLibraryExt(const char* libpath, int flag, native_bridge_namespace_t* ns);
// Returns vendor namespace if it is enabled for the device and null otherwise
native_bridge_namespace_t* NativeBridgeGetVendorNamespace();
// Native bridge interfaces to runtime.
struct NativeBridgeCallbacks {
// Version number of the interface.
@ -348,6 +351,15 @@ struct NativeBridgeCallbacks {
// Starting with v3, NativeBridge has two scenarios: with/without namespace.
// Use loadLibrary instead in non-namespace scenario.
void* (*loadLibraryExt)(const char* libpath, int flag, native_bridge_namespace_t* ns);
// Get native bridge version of vendor namespace.
// The vendor namespace is the namespace used to load vendor public libraries.
// With O release this namespace can be different from the default namespace.
// For the devices without enable vendor namespaces this function should return null
//
// Returns:
// vendor namespace or null if it was not set up for the device
native_bridge_namespace_t* (*getVendorNamespace)();
};
// Runtime interfaces to native bridge.

View File

@ -0,0 +1 @@
../.clang-format-2

View File

@ -85,12 +85,14 @@ static NativeBridgeState state = NativeBridgeState::kNotSetup;
// Nativebridge implementation.
// Used by isCompatibleWith() which is introduced in v2.
enum NativeBridgeImplementationVersion {
// first version, not used.
DEFAULT_VERSION = 1,
// The version which signal semantic is introduced.
SIGNAL_VERSION = 2,
// The version which namespace semantic is introduced.
NAMESPACE_VERSION = 3,
// first version, not used.
DEFAULT_VERSION = 1,
// The version which signal semantic is introduced.
SIGNAL_VERSION = 2,
// The version which namespace semantic is introduced.
NAMESPACE_VERSION = 3,
// The version with vendor namespaces
VENDOR_NAMESPACE_VERSION = 4,
};
// Whether we had an error at some point.
@ -621,6 +623,14 @@ bool NativeBridgeLinkNamespaces(native_bridge_namespace_t* from, native_bridge_n
return false;
}
native_bridge_namespace_t* NativeBridgeGetVendorNamespace() {
if (!NativeBridgeInitialized() || !isCompatibleWith(VENDOR_NAMESPACE_VERSION)) {
return nullptr;
}
return callbacks->getVendorNamespace();
}
void* NativeBridgeLoadLibraryExt(const char* libpath, int flag, native_bridge_namespace_t* ns) {
if (NativeBridgeInitialized()) {
if (isCompatibleWith(NAMESPACE_VERSION)) {

View File

@ -0,0 +1 @@
../.clang-format-2

View File

@ -124,6 +124,8 @@ extern bool android_link_namespaces(android_namespace_t* from,
*/
extern void android_get_LD_LIBRARY_PATH(char* buffer, size_t buffer_size);
extern android_namespace_t* android_get_exported_namespace(const char* name);
__END_DECLS
#endif /* __ANDROID_DLEXT_NAMESPACES_H__ */

View File

@ -83,6 +83,12 @@ static constexpr const char* kPublicNativeLibrariesSystemConfigPathFromRoot =
static constexpr const char* kPublicNativeLibrariesVendorConfig =
"/vendor/etc/public.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
// to use to load vendor libraries to separate namespace with controlled interface between
// vendor and system namespaces.
static constexpr const char* kVendorNamespaceName = "sphal";
// (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.
@ -170,11 +176,23 @@ class LibraryNamespaces {
return false;
}
if (!android_link_namespaces(ns, nullptr, public_libraries_.c_str())) {
// Note that when vendor_ns is not configured this function will return nullptr
// and it will result in linking vendor_public_libraries_ to the default namespace
// 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())) {
*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();
return false;
}
}
native_loader_ns = NativeLoaderNamespace(ns);
} else {
native_bridge_namespace_t* ns = NativeBridgeCreateNamespace("classloader-namespace",
@ -183,14 +201,24 @@ class LibraryNamespaces {
namespace_type,
permitted_path.c_str(),
parent_ns.get_native_bridge_ns());
if (ns == nullptr) {
*error_msg = NativeBridgeGetError();
return false;
}
if (!NativeBridgeLinkNamespaces(ns, nullptr, public_libraries_.c_str())) {
native_bridge_namespace_t* vendor_ns = NativeBridgeGetVendorNamespace();
if (!NativeBridgeLinkNamespaces(ns, nullptr, system_public_libraries_.c_str())) {
*error_msg = NativeBridgeGetError();
return false;
}
if (!vendor_public_libraries_.empty()) {
if (!NativeBridgeLinkNamespaces(ns, vendor_ns, vendor_public_libraries_.c_str())) {
*error_msg = NativeBridgeGetError();
return false;
}
}
native_loader_ns = NativeLoaderNamespace(ns);
@ -249,9 +277,6 @@ class LibraryNamespaces {
}
}
// This file is optional, quietly ignore if the file does not exist.
ReadConfig(kPublicNativeLibrariesVendorConfig, &sonames);
// android_init_namespaces() expects all the public libraries
// to be loaded so that they can be found by soname alone.
//
@ -266,7 +291,13 @@ class LibraryNamespaces {
soname.c_str(), dlerror());
}
public_libraries_ = base::Join(sonames, ':');
system_public_libraries_ = base::Join(sonames, ':');
sonames.clear();
// This file is optional, quietly ignore if the file does not exist.
ReadConfig(kPublicNativeLibrariesVendorConfig, &sonames);
vendor_public_libraries_ = base::Join(sonames, ':');
}
void Reset() {
@ -325,7 +356,7 @@ class LibraryNamespaces {
// 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(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();
@ -334,10 +365,10 @@ class LibraryNamespaces {
// and now initialize native bridge namespaces if necessary.
if (NativeBridgeInitialized()) {
initialized_ = NativeBridgeInitAnonymousNamespace(
public_libraries_.c_str(), is_native_bridge ? library_path : nullptr);
if (!initialized_) {
*error_msg = NativeBridgeGetError();
initialized_ = NativeBridgeInitAnonymousNamespace(system_public_libraries_.c_str(),
is_native_bridge ? library_path : nullptr);
if (!initialized_) {
*error_msg = NativeBridgeGetError();
}
}
@ -371,8 +402,8 @@ class LibraryNamespaces {
bool initialized_;
std::vector<std::pair<jweak, NativeLoaderNamespace>> namespaces_;
std::string public_libraries_;
std::string system_public_libraries_;
std::string vendor_public_libraries_;
DISALLOW_COPY_AND_ASSIGN(LibraryNamespaces);
};