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

am: 1238292db5

Change-Id: I9200efa2d6c3f0d1b96b81e5c065f85f8b96b06f
This commit is contained in:
Zhenhua WANG 2017-04-07 21:54:57 +00:00 committed by android-build-merger
commit 21c8a291c5
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. // Use NativeBridgeIsSupported() instead in non-namespace scenario.
bool NativeBridgeIsPathSupported(const char* path); 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. // Starting with v3, NativeBridge has two scenarios: with/without namespace.
// Should not use in non-namespace scenario. // Should not use in non-namespace scenario.
bool NativeBridgeInitNamespace(const char* public_ns_sonames, bool NativeBridgeInitAnonymousNamespace(const char* public_ns_sonames,
const char* anon_ns_library_path); 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. // Starting with v3, NativeBridge has two scenarios: with/without namespace.
// Should not use in non-namespace scenario. // 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, const char* permitted_when_isolated_path,
native_bridge_namespace_t* parent_ns); 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. // 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. // Starting with v3, NativeBridge has two scenarios: with/without namespace.
// Use NativeBridgeLoadLibrary() instead in non-namespace scenario. // Use NativeBridgeLoadLibrary() instead in non-namespace scenario.
@ -152,7 +173,7 @@ struct NativeBridgeCallbacks {
// Parameters: // Parameters:
// runtime_cbs [IN] the pointer to NativeBridgeRuntimeCallbacks. // runtime_cbs [IN] the pointer to NativeBridgeRuntimeCallbacks.
// Returns: // Returns:
// true iff initialization was successful. // true if initialization was successful.
bool (*initialize)(const NativeBridgeRuntimeCallbacks* runtime_cbs, const char* private_dir, bool (*initialize)(const NativeBridgeRuntimeCallbacks* runtime_cbs, const char* private_dir,
const char* instruction_set); const char* instruction_set);
@ -194,10 +215,10 @@ struct NativeBridgeCallbacks {
// instruction set. // instruction set.
// //
// Parameters: // Parameters:
// instruction_set [IN] the instruction set of the app // instruction_set [IN] the instruction set of the app
// Returns: // Returns:
// NULL if not supported by native bridge. // NULL if not supported by native bridge.
// Otherwise, return all environment values to be set after fork. // Otherwise, return all environment values to be set after fork.
const struct NativeBridgeRuntimeValues* (*getAppEnv)(const char* instruction_set); const struct NativeBridgeRuntimeValues* (*getAppEnv)(const char* instruction_set);
// Added callbacks in version 2. // Added callbacks in version 2.
@ -206,9 +227,9 @@ struct NativeBridgeCallbacks {
// forwards- or backwards-compatible, and libnativebridge will then stop using it. // forwards- or backwards-compatible, and libnativebridge will then stop using it.
// //
// Parameters: // Parameters:
// bridge_version [IN] the version of libnativebridge. // bridge_version [IN] the version of libnativebridge.
// Returns: // 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); bool (*isCompatibleWith)(uint32_t bridge_version);
// A callback to retrieve a native bridge's signal handler for the specified signal. The runtime // 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. // that will potentially lead to cycles.
// //
// Parameters: // 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. // supported by the runtime.
// Returns: // Returns:
// NULL if the native bridge doesn't use a handler or doesn't want it to be managed by the // NULL if the native bridge doesn't use a handler or doesn't want it to be managed by the
// runtime. // runtime.
// Otherwise, a pointer to the signal handler. // Otherwise, a pointer to the signal handler.
NativeBridgeSignalHandlerFn (*getSignalHandler)(int signal); NativeBridgeSignalHandlerFn (*getSignalHandler)(int signal);
// Added callbacks in version 3. // Added callbacks in version 3.
@ -231,7 +252,7 @@ struct NativeBridgeCallbacks {
// to zero then the dynamic library is unloaded. // to zero then the dynamic library is unloaded.
// //
// Parameters: // Parameters:
// handle [IN] the handler of a dynamic library. // handle [IN] the handler of a dynamic library.
// //
// Returns: // Returns:
// 0 on success, and nonzero on error. // 0 on success, and nonzero on error.
@ -257,33 +278,36 @@ struct NativeBridgeCallbacks {
// Use isSupported instead in non-namespace scenario. // Use isSupported instead in non-namespace scenario.
bool (*isPathSupported)(const char* library_path); bool (*isPathSupported)(const char* library_path);
// Initializes anonymous namespace at native bridge side and pass the key of // Initializes anonymous namespace at native bridge side.
// two namespaces(default and anonymous) owned by dynamic linker to native bridge. // 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: // Parameters:
// public_ns_sonames [IN] the name of "public" libraries. // public_ns_sonames [IN] the name of "public" libraries.
// anon_ns_library_path [IN] the library search path of (anonymous) namespace. // anon_ns_library_path [IN] the library search path of (anonymous) namespace.
// Returns: // Returns:
// true if the pass is ok. // true if the pass is ok.
// Otherwise, false. // Otherwise, false.
// //
// Starting with v3, NativeBridge has two scenarios: with/without namespace. // Starting with v3, NativeBridge has two scenarios: with/without namespace.
// Should not use in non-namespace scenario. // Should not use in non-namespace scenario.
bool (*initNamespace)(const char* public_ns_sonames, bool (*initAnonymousNamespace)(const char* public_ns_sonames, const char* anon_ns_library_path);
const char* anon_ns_library_path);
// Create new namespace in which native libraries will be loaded.
// Create a namespace and pass the key of releated namespaces to native bridge. // NativeBridge's peer of android_create_namespace() of dynamic linker.
// //
// Parameters: // Parameters:
// name [IN] the name of the namespace. // name [IN] the name of the namespace.
// ld_library_path [IN] the first set of library search paths 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. // default_library_path [IN] the second set of library search path of the namespace.
// type [IN] the attribute of the namespace. // type [IN] the attribute of the namespace.
// permitted_when_isolated_path [IN] the permitted path for isolated namespace(if it is). // 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. // parent_ns [IN] the pointer of the parent namespace to be inherited from.
// Returns: // 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. // Starting with v3, NativeBridge has two scenarios: with/without namespace.
// Should not use in non-namespace scenario. // Should not use in non-namespace scenario.
@ -294,7 +318,25 @@ struct NativeBridgeCallbacks {
const char* permitted_when_isolated_path, const char* permitted_when_isolated_path,
native_bridge_namespace_t* parent_ns); 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. // Load a shared library within a namespace.
// NativeBridge's peer of android_dlopen_ext() of dynamic linker, only supports namespace
// extension.
// //
// Parameters: // Parameters:
// libpath [IN] path to the shared library // libpath [IN] path to the shared library

View file

@ -573,11 +573,11 @@ bool NativeBridgeIsPathSupported(const char* path) {
return false; return false;
} }
bool NativeBridgeInitNamespace(const char* public_ns_sonames, bool NativeBridgeInitAnonymousNamespace(const char* public_ns_sonames,
const char* anon_ns_library_path) { const char* anon_ns_library_path) {
if (NativeBridgeInitialized()) { if (NativeBridgeInitialized()) {
if (isCompatibleWith(NAMESPACE_VERSION)) { 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 { } else {
ALOGE("not compatible with version %d, cannot init namespace", NAMESPACE_VERSION); 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; 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) { void* NativeBridgeLoadLibraryExt(const char* libpath, int flag, native_bridge_namespace_t* ns) {
if (NativeBridgeInitialized()) { if (NativeBridgeInitialized()) {
if (isCompatibleWith(NAMESPACE_VERSION)) { if (isCompatibleWith(NAMESPACE_VERSION)) {

View file

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

View file

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

View file

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

View file

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