Merge "NativeBridge: add "linked namespace" semantic corresponding to linker"

This commit is contained in:
Treehugger Robot 2017-04-07 21:46:14 +00:00 committed by Gerrit Code Review
commit 1238292db5
6 changed files with 137 additions and 73 deletions

View File

@ -116,14 +116,25 @@ struct native_bridge_namespace_t;
// Use NativeBridgeIsSupported() instead in non-namespace scenario.
bool NativeBridgeIsPathSupported(const char* path);
// Initializes public and anonymous namespace at native bridge side.
// Initializes anonymous namespace.
// NativeBridge's peer of android_init_anonymous_namespace() of dynamic linker.
//
// The anonymous namespace is used in the case when a NativeBridge implementation
// cannot identify the caller of dlopen/dlsym which happens for the code not loaded
// by dynamic linker; for example calls from the mono-compiled code.
//
// Starting with v3, NativeBridge has two scenarios: with/without namespace.
// Should not use in non-namespace scenario.
bool NativeBridgeInitNamespace(const char* public_ns_sonames,
const char* anon_ns_library_path);
bool NativeBridgeInitAnonymousNamespace(const char* public_ns_sonames,
const char* anon_ns_library_path);
// Create a namespace and pass the key of related namespaces to native bridge.
// Create new namespace in which native libraries will be loaded.
// NativeBridge's peer of android_create_namespace() of dynamic linker.
//
// The libraries in the namespace are searched by folowing order:
// 1. ld_library_path (Think of this as namespace-local LD_LIBRARY_PATH)
// 2. In directories specified by DT_RUNPATH of the "needed by" binary.
// 3. deault_library_path (This of this as namespace-local default library path)
//
// Starting with v3, NativeBridge has two scenarios: with/without namespace.
// Should not use in non-namespace scenario.
@ -134,7 +145,17 @@ native_bridge_namespace_t* NativeBridgeCreateNamespace(const char* name,
const char* permitted_when_isolated_path,
native_bridge_namespace_t* parent_ns);
// Creates a link which shares some libraries from one namespace to another.
// NativeBridge's peer of android_link_namespaces() of dynamic linker.
//
// Starting with v3, NativeBridge has two scenarios: with/without namespace.
// Should not use in non-namespace scenario.
bool NativeBridgeLinkNamespaces(native_bridge_namespace_t* from, native_bridge_namespace_t* to,
const char* shared_libs_sonames);
// Load a shared library with namespace key that is supported by the native bridge.
// NativeBridge's peer of android_dlopen_ext() of dynamic linker, only supports namespace
// extension.
//
// Starting with v3, NativeBridge has two scenarios: with/without namespace.
// Use NativeBridgeLoadLibrary() instead in non-namespace scenario.
@ -152,7 +173,7 @@ struct NativeBridgeCallbacks {
// Parameters:
// runtime_cbs [IN] the pointer to NativeBridgeRuntimeCallbacks.
// Returns:
// true iff initialization was successful.
// true if initialization was successful.
bool (*initialize)(const NativeBridgeRuntimeCallbacks* runtime_cbs, const char* private_dir,
const char* instruction_set);
@ -194,10 +215,10 @@ struct NativeBridgeCallbacks {
// instruction set.
//
// Parameters:
// instruction_set [IN] the instruction set of the app
// instruction_set [IN] the instruction set of the app
// Returns:
// NULL if not supported by native bridge.
// Otherwise, return all environment values to be set after fork.
// NULL if not supported by native bridge.
// Otherwise, return all environment values to be set after fork.
const struct NativeBridgeRuntimeValues* (*getAppEnv)(const char* instruction_set);
// Added callbacks in version 2.
@ -206,9 +227,9 @@ struct NativeBridgeCallbacks {
// forwards- or backwards-compatible, and libnativebridge will then stop using it.
//
// Parameters:
// bridge_version [IN] the version of libnativebridge.
// bridge_version [IN] the version of libnativebridge.
// Returns:
// true iff the native bridge supports the given version of libnativebridge.
// true if the native bridge supports the given version of libnativebridge.
bool (*isCompatibleWith)(uint32_t bridge_version);
// A callback to retrieve a native bridge's signal handler for the specified signal. The runtime
@ -217,12 +238,12 @@ struct NativeBridgeCallbacks {
// that will potentially lead to cycles.
//
// Parameters:
// signal [IN] the signal for which the handler is asked for. Currently, only SIGSEGV is
// signal [IN] the signal for which the handler is asked for. Currently, only SIGSEGV is
// supported by the runtime.
// Returns:
// NULL if the native bridge doesn't use a handler or doesn't want it to be managed by the
// runtime.
// Otherwise, a pointer to the signal handler.
// NULL if the native bridge doesn't use a handler or doesn't want it to be managed by the
// runtime.
// Otherwise, a pointer to the signal handler.
NativeBridgeSignalHandlerFn (*getSignalHandler)(int signal);
// Added callbacks in version 3.
@ -231,7 +252,7 @@ struct NativeBridgeCallbacks {
// to zero then the dynamic library is unloaded.
//
// Parameters:
// handle [IN] the handler of a dynamic library.
// handle [IN] the handler of a dynamic library.
//
// Returns:
// 0 on success, and nonzero on error.
@ -257,33 +278,36 @@ struct NativeBridgeCallbacks {
// Use isSupported instead in non-namespace scenario.
bool (*isPathSupported)(const char* library_path);
// Initializes anonymous namespace at native bridge side and pass the key of
// two namespaces(default and anonymous) owned by dynamic linker to native bridge.
// Initializes anonymous namespace at native bridge side.
// NativeBridge's peer of android_init_anonymous_namespace() of dynamic linker.
//
// The anonymous namespace is used in the case when a NativeBridge implementation
// cannot identify the caller of dlopen/dlsym which happens for the code not loaded
// by dynamic linker; for example calls from the mono-compiled code.
//
// Parameters:
// public_ns_sonames [IN] the name of "public" libraries.
// anon_ns_library_path [IN] the library search path of (anonymous) namespace.
// public_ns_sonames [IN] the name of "public" libraries.
// anon_ns_library_path [IN] the library search path of (anonymous) namespace.
// Returns:
// true if the pass is ok.
// Otherwise, false.
// true if the pass is ok.
// Otherwise, false.
//
// Starting with v3, NativeBridge has two scenarios: with/without namespace.
// Should not use in non-namespace scenario.
bool (*initNamespace)(const char* public_ns_sonames,
const char* anon_ns_library_path);
bool (*initAnonymousNamespace)(const char* public_ns_sonames, const char* anon_ns_library_path);
// Create a namespace and pass the key of releated namespaces to native bridge.
// Create new namespace in which native libraries will be loaded.
// NativeBridge's peer of android_create_namespace() of dynamic linker.
//
// Parameters:
// name [IN] the name of the namespace.
// ld_library_path [IN] the first set of library search paths of the namespace.
// default_library_path [IN] the second set of library search path of the namespace.
// type [IN] the attribute of the namespace.
// permitted_when_isolated_path [IN] the permitted path for isolated namespace(if it is).
// parent_ns [IN] the pointer of the parent namespace to be inherited from.
// name [IN] the name of the namespace.
// ld_library_path [IN] the first set of library search paths of the namespace.
// default_library_path [IN] the second set of library search path of the namespace.
// type [IN] the attribute of the namespace.
// permitted_when_isolated_path [IN] the permitted path for isolated namespace(if it is).
// parent_ns [IN] the pointer of the parent namespace to be inherited from.
// Returns:
// native_bridge_namespace_t* for created namespace or nullptr in the case of error.
// native_bridge_namespace_t* for created namespace or nullptr in the case of error.
//
// Starting with v3, NativeBridge has two scenarios: with/without namespace.
// Should not use in non-namespace scenario.
@ -294,7 +318,25 @@ struct NativeBridgeCallbacks {
const char* permitted_when_isolated_path,
native_bridge_namespace_t* parent_ns);
// Creates a link which shares some libraries from one namespace to another.
// NativeBridge's peer of android_link_namespaces() of dynamic linker.
//
// Parameters:
// from [IN] the namespace where libraries are accessed.
// to [IN] the namespace where libraries are loaded.
// shared_libs_sonames [IN] the libraries to be shared.
//
// Returns:
// Whether successed or not.
//
// Starting with v3, NativeBridge has two scenarios: with/without namespace.
// Should not use in non-namespace scenario.
bool (*linkNamespaces)(native_bridge_namespace_t* from, native_bridge_namespace_t* to,
const char* shared_libs_sonames);
// Load a shared library within a namespace.
// NativeBridge's peer of android_dlopen_ext() of dynamic linker, only supports namespace
// extension.
//
// Parameters:
// libpath [IN] path to the shared library

View File

@ -573,11 +573,11 @@ bool NativeBridgeIsPathSupported(const char* path) {
return false;
}
bool NativeBridgeInitNamespace(const char* public_ns_sonames,
const char* anon_ns_library_path) {
bool NativeBridgeInitAnonymousNamespace(const char* public_ns_sonames,
const char* anon_ns_library_path) {
if (NativeBridgeInitialized()) {
if (isCompatibleWith(NAMESPACE_VERSION)) {
return callbacks->initNamespace(public_ns_sonames, anon_ns_library_path);
return callbacks->initAnonymousNamespace(public_ns_sonames, anon_ns_library_path);
} else {
ALOGE("not compatible with version %d, cannot init namespace", NAMESPACE_VERSION);
}
@ -608,6 +608,19 @@ native_bridge_namespace_t* NativeBridgeCreateNamespace(const char* name,
return nullptr;
}
bool NativeBridgeLinkNamespaces(native_bridge_namespace_t* from, native_bridge_namespace_t* to,
const char* shared_libs_sonames) {
if (NativeBridgeInitialized()) {
if (isCompatibleWith(NAMESPACE_VERSION)) {
return callbacks->linkNamespaces(from, to, shared_libs_sonames);
} else {
ALOGE("not compatible with version %d, cannot init namespace", NAMESPACE_VERSION);
}
}
return false;
}
void* NativeBridgeLoadLibraryExt(const char* libpath, int flag, native_bridge_namespace_t* ns) {
if (NativeBridgeInitialized()) {
if (isCompatibleWith(NAMESPACE_VERSION)) {

View File

@ -24,7 +24,7 @@ test_src_files := \
NativeBridge3UnloadLibrary_test.cpp \
NativeBridge3GetError_test.cpp \
NativeBridge3IsPathSupported_test.cpp \
NativeBridge3InitNamespace_test.cpp \
NativeBridge3InitAnonymousNamespace_test.cpp \
NativeBridge3CreateNamespace_test.cpp \
NativeBridge3LoadLibraryExt_test.cpp

View File

@ -76,8 +76,8 @@ extern "C" bool native_bridge3_isPathSupported(const char* /* path */) {
return true;
}
extern "C" bool native_bridge3_initNamespace(const char* /* public_ns_sonames */,
const char* /* anon_ns_library_path */) {
extern "C" bool native_bridge3_initAnonymousNamespace(const char* /* public_ns_sonames */,
const char* /* anon_ns_library_path */) {
return true;
}
@ -91,30 +91,34 @@ native_bridge3_createNamespace(const char* /* name */,
return nullptr;
}
extern "C" bool native_bridge3_linkNamespaces(android::native_bridge_namespace_t* /* from */,
android::native_bridge_namespace_t* /* to */,
const char* /* shared_libs_soname */) {
return true;
}
extern "C" void* native_bridge3_loadLibraryExt(const char* /* libpath */,
int /* flag */,
android::native_bridge_namespace_t* /* ns */) {
return nullptr;
}
android::NativeBridgeCallbacks NativeBridgeItf {
// v1
.version = 3,
.initialize = &native_bridge3_initialize,
.loadLibrary = &native_bridge3_loadLibrary,
.getTrampoline = &native_bridge3_getTrampoline,
.isSupported = &native_bridge3_isSupported,
.getAppEnv = &native_bridge3_getAppEnv,
// v2
.isCompatibleWith = &native_bridge3_isCompatibleWith,
.getSignalHandler = &native_bridge3_getSignalHandler,
// v3
.unloadLibrary = &native_bridge3_unloadLibrary,
.getError = &native_bridge3_getError,
.isPathSupported = &native_bridge3_isPathSupported,
.initNamespace = &native_bridge3_initNamespace,
.createNamespace = &native_bridge3_createNamespace,
.loadLibraryExt = &native_bridge3_loadLibraryExt
};
android::NativeBridgeCallbacks NativeBridgeItf{
// v1
.version = 3,
.initialize = &native_bridge3_initialize,
.loadLibrary = &native_bridge3_loadLibrary,
.getTrampoline = &native_bridge3_getTrampoline,
.isSupported = &native_bridge3_isSupported,
.getAppEnv = &native_bridge3_getAppEnv,
// v2
.isCompatibleWith = &native_bridge3_isCompatibleWith,
.getSignalHandler = &native_bridge3_getSignalHandler,
// v3
.unloadLibrary = &native_bridge3_unloadLibrary,
.getError = &native_bridge3_getError,
.isPathSupported = &native_bridge3_isPathSupported,
.initAnonymousNamespace = &native_bridge3_initAnonymousNamespace,
.createNamespace = &native_bridge3_createNamespace,
.linkNamespaces = &native_bridge3_linkNamespaces,
.loadLibraryExt = &native_bridge3_loadLibraryExt};

View File

@ -20,20 +20,20 @@ namespace android {
constexpr const char* kNativeBridgeLibrary3 = "libnativebridge3-dummy.so";
TEST_F(NativeBridgeTest, V3_InitNamespace) {
// Init
ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary3, nullptr));
ASSERT_TRUE(NativeBridgeAvailable());
ASSERT_TRUE(PreInitializeNativeBridge(".", "isa"));
ASSERT_TRUE(NativeBridgeAvailable());
ASSERT_TRUE(InitializeNativeBridge(nullptr, nullptr));
ASSERT_TRUE(NativeBridgeAvailable());
TEST_F(NativeBridgeTest, V3_InitAnonymousNamespace) {
// Init
ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary3, nullptr));
ASSERT_TRUE(NativeBridgeAvailable());
ASSERT_TRUE(PreInitializeNativeBridge(".", "isa"));
ASSERT_TRUE(NativeBridgeAvailable());
ASSERT_TRUE(InitializeNativeBridge(nullptr, nullptr));
ASSERT_TRUE(NativeBridgeAvailable());
ASSERT_EQ(3U, NativeBridgeGetVersion());
ASSERT_EQ(true, NativeBridgeInitNamespace(nullptr, nullptr));
ASSERT_EQ(3U, NativeBridgeGetVersion());
ASSERT_EQ(true, NativeBridgeInitAnonymousNamespace(nullptr, nullptr));
// Clean-up code_cache
ASSERT_EQ(0, rmdir(kCodeCache));
// Clean-up code_cache
ASSERT_EQ(0, rmdir(kCodeCache));
}
} // namespace android

View File

@ -183,6 +183,11 @@ class LibraryNamespaces {
return false;
}
if (!NativeBridgeLinkNamespaces(ns, nullptr, public_libraries_.c_str())) {
*error_msg = NativeBridgeGetError();
return false;
}
native_loader_ns = NativeLoaderNamespace(ns);
}
@ -324,8 +329,8 @@ class LibraryNamespaces {
// and now initialize native bridge namespaces if necessary.
if (NativeBridgeInitialized()) {
initialized_ = NativeBridgeInitNamespace(public_libraries_.c_str(),
is_native_bridge ? library_path : nullptr);
initialized_ = NativeBridgeInitAnonymousNamespace(public_libraries_.c_str(),
is_native_bridge ? library_path : nullptr);
if (!initialized_) {
*error_msg = NativeBridgeGetError();
}