Merge "Upgrade native bridge to version 3 to support namespace"
am: 28c0c0762e
Change-Id: Ic4263e89f59b1ad34f1f8f28b52f4b45a4df351d
This commit is contained in:
commit
996cfc70a0
15 changed files with 845 additions and 68 deletions
|
@ -62,12 +62,19 @@ bool NativeBridgeAvailable();
|
|||
bool NativeBridgeInitialized();
|
||||
|
||||
// Load a shared library that is supported by the native bridge.
|
||||
//
|
||||
// Starting with v3, NativeBridge has two scenarios: with/without namespace.
|
||||
// Use NativeBridgeLoadLibraryExt() instead in namespace scenario.
|
||||
void* NativeBridgeLoadLibrary(const char* libpath, int flag);
|
||||
|
||||
// Get a native bridge trampoline for specified native method.
|
||||
void* NativeBridgeGetTrampoline(void* handle, const char* name, const char* shorty, uint32_t len);
|
||||
|
||||
// True if native library is valid and is for an ABI that is supported by native bridge.
|
||||
// True if native library paths are valid and is for an ABI that is supported by native bridge.
|
||||
// The *libpath* must point to a library.
|
||||
//
|
||||
// Starting with v3, NativeBridge has two scenarios: with/without namespace.
|
||||
// Use NativeBridgeIsPathSupported() instead in namespace scenario.
|
||||
bool NativeBridgeIsSupported(const char* libpath);
|
||||
|
||||
// Returns the version number of the native bridge. This information is available after a
|
||||
|
@ -91,6 +98,48 @@ bool NativeBridgeError();
|
|||
// This functionality is exposed mainly for testing.
|
||||
bool NativeBridgeNameAcceptable(const char* native_bridge_library_filename);
|
||||
|
||||
// Decrements the reference count on the dynamic library handler. If the reference count drops
|
||||
// to zero then the dynamic library is unloaded.
|
||||
int NativeBridgeUnloadLibrary(void* handle);
|
||||
|
||||
// Get last error message of native bridge when fail to load library or search symbol.
|
||||
// This is reflection of dlerror() for native bridge.
|
||||
char* NativeBridgeGetError();
|
||||
|
||||
struct native_bridge_namespace_t;
|
||||
|
||||
// True if native library paths are valid and is for an ABI that is supported by native bridge.
|
||||
// Different from NativeBridgeIsSupported(), the *path* here must be a directory containing
|
||||
// libraries of an ABI.
|
||||
//
|
||||
// Starting with v3, NativeBridge has two scenarios: with/without namespace.
|
||||
// Use NativeBridgeIsSupported() instead in non-namespace scenario.
|
||||
bool NativeBridgeIsPathSupported(const char* path);
|
||||
|
||||
// Initializes public and anonymous namespace at native bridge side.
|
||||
//
|
||||
// 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);
|
||||
|
||||
// Create a namespace and pass the key of related namespaces to native bridge.
|
||||
//
|
||||
// Starting with v3, NativeBridge has two scenarios: with/without namespace.
|
||||
// Should not use in non-namespace scenario.
|
||||
native_bridge_namespace_t* NativeBridgeCreateNamespace(const char* name,
|
||||
const char* ld_library_path,
|
||||
const char* default_library_path,
|
||||
uint64_t type,
|
||||
const char* permitted_when_isolated_path,
|
||||
native_bridge_namespace_t* parent_ns);
|
||||
|
||||
// Load a shared library with namespace key that is supported by the native bridge.
|
||||
//
|
||||
// Starting with v3, NativeBridge has two scenarios: with/without namespace.
|
||||
// Use NativeBridgeLoadLibrary() instead in non-namespace scenario.
|
||||
void* NativeBridgeLoadLibraryExt(const char* libpath, int flag, native_bridge_namespace_t* ns);
|
||||
|
||||
// Native bridge interfaces to runtime.
|
||||
struct NativeBridgeCallbacks {
|
||||
// Version number of the interface.
|
||||
|
@ -114,6 +163,9 @@ struct NativeBridgeCallbacks {
|
|||
// flag [IN] the stardard RTLD_XXX defined in bionic dlfcn.h
|
||||
// Returns:
|
||||
// The opaque handle of the shared library if sucessful, otherwise NULL
|
||||
//
|
||||
// Starting with v3, NativeBridge has two scenarios: with/without namespace.
|
||||
// Use loadLibraryExt instead in namespace scenario.
|
||||
void* (*loadLibrary)(const char* libpath, int flag);
|
||||
|
||||
// Get a native bridge trampoline for specified native method. The trampoline has same
|
||||
|
@ -133,6 +185,9 @@ struct NativeBridgeCallbacks {
|
|||
// libpath [IN] path to the shared library
|
||||
// Returns:
|
||||
// TRUE if library is supported by native bridge, FALSE otherwise
|
||||
//
|
||||
// Starting with v3, NativeBridge has two scenarios: with/without namespace.
|
||||
// Use isPathSupported instead in namespace scenario.
|
||||
bool (*isSupported)(const char* libpath);
|
||||
|
||||
// Provide environment values required by the app running with native bridge according to the
|
||||
|
@ -169,6 +224,88 @@ struct NativeBridgeCallbacks {
|
|||
// runtime.
|
||||
// Otherwise, a pointer to the signal handler.
|
||||
NativeBridgeSignalHandlerFn (*getSignalHandler)(int signal);
|
||||
|
||||
// Added callbacks in version 3.
|
||||
|
||||
// Decrements the reference count on the dynamic library handler. If the reference count drops
|
||||
// to zero then the dynamic library is unloaded.
|
||||
//
|
||||
// Parameters:
|
||||
// handle [IN] the handler of a dynamic library.
|
||||
//
|
||||
// Returns:
|
||||
// 0 on success, and nonzero on error.
|
||||
int (*unloadLibrary)(void* handle);
|
||||
|
||||
// Dump the last failure message of native bridge when fail to load library or search symbol.
|
||||
//
|
||||
// Parameters:
|
||||
//
|
||||
// Returns:
|
||||
// A string describing the most recent error that occurred when load library
|
||||
// or lookup symbol via native bridge.
|
||||
char* (*getError)();
|
||||
|
||||
// Check whether library paths are supported by native bridge.
|
||||
//
|
||||
// Parameters:
|
||||
// library_path [IN] search paths for native libraries (directories separated by ':')
|
||||
// Returns:
|
||||
// TRUE if libraries within search paths are supported by native bridge, FALSE otherwise
|
||||
//
|
||||
// Starting with v3, NativeBridge has two scenarios: with/without namespace.
|
||||
// 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.
|
||||
//
|
||||
// Parameters:
|
||||
// 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.
|
||||
//
|
||||
// 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);
|
||||
|
||||
|
||||
// Create a namespace and pass the key of releated namespaces to native bridge.
|
||||
//
|
||||
// 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.
|
||||
// Returns:
|
||||
// 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.
|
||||
native_bridge_namespace_t* (*createNamespace)(const char* name,
|
||||
const char* ld_library_path,
|
||||
const char* default_library_path,
|
||||
uint64_t type,
|
||||
const char* permitted_when_isolated_path,
|
||||
native_bridge_namespace_t* parent_ns);
|
||||
|
||||
// Load a shared library within a namespace.
|
||||
//
|
||||
// Parameters:
|
||||
// libpath [IN] path to the shared library
|
||||
// flag [IN] the stardard RTLD_XXX defined in bionic dlfcn.h
|
||||
// ns [IN] the pointer of the namespace in which the library should be loaded.
|
||||
// Returns:
|
||||
// The opaque handle of the shared library if sucessful, otherwise NULL
|
||||
//
|
||||
// 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);
|
||||
};
|
||||
|
||||
// Runtime interfaces to native bridge.
|
||||
|
|
|
@ -80,6 +80,19 @@ static const char* GetNativeBridgeStateString(NativeBridgeState state) {
|
|||
// Current state of the native bridge.
|
||||
static NativeBridgeState state = NativeBridgeState::kNotSetup;
|
||||
|
||||
// The version of NativeBridge implementation.
|
||||
// Different Nativebridge interface needs the service of different version of
|
||||
// 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,
|
||||
};
|
||||
|
||||
// Whether we had an error at some point.
|
||||
static bool had_error = false;
|
||||
|
||||
|
@ -100,8 +113,6 @@ static char* app_code_cache_dir = nullptr;
|
|||
// and hard code the directory name again here.
|
||||
static constexpr const char* kCodeCacheDir = "code_cache";
|
||||
|
||||
static constexpr uint32_t kLibNativeBridgeVersion = 2;
|
||||
|
||||
// Characters allowed in a native bridge filename. The first character must
|
||||
// be in [a-zA-Z] (expected 'l' for "libx"). The rest must be in [a-zA-Z0-9._-].
|
||||
static bool CharacterAllowed(char c, bool first) {
|
||||
|
@ -152,19 +163,18 @@ bool NativeBridgeNameAcceptable(const char* nb_library_filename) {
|
|||
}
|
||||
}
|
||||
|
||||
static bool VersionCheck(const NativeBridgeCallbacks* cb) {
|
||||
// The policy of invoking Nativebridge changed in v3 with/without namespace.
|
||||
// Suggest Nativebridge implementation not maintain backward-compatible.
|
||||
static bool isCompatibleWith(const uint32_t version) {
|
||||
// Libnativebridge is now designed to be forward-compatible. So only "0" is an unsupported
|
||||
// version.
|
||||
if (cb == nullptr || cb->version == 0) {
|
||||
if (callbacks == nullptr || callbacks->version == 0 || version == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If this is a v2+ bridge, it may not be forwards- or backwards-compatible. Check.
|
||||
if (cb->version >= 2) {
|
||||
if (!callbacks->isCompatibleWith(kLibNativeBridgeVersion)) {
|
||||
// TODO: Scan which version is supported, and fall back to handle it.
|
||||
return false;
|
||||
}
|
||||
if (callbacks->version >= SIGNAL_VERSION) {
|
||||
return callbacks->isCompatibleWith(version);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -205,7 +215,7 @@ bool LoadNativeBridge(const char* nb_library_filename,
|
|||
callbacks = reinterpret_cast<NativeBridgeCallbacks*>(dlsym(handle,
|
||||
kNativeBridgeInterfaceSymbol));
|
||||
if (callbacks != nullptr) {
|
||||
if (VersionCheck(callbacks)) {
|
||||
if (isCompatibleWith(NAMESPACE_VERSION)) {
|
||||
// Store the handle for later.
|
||||
native_bridge_handle = handle;
|
||||
} else {
|
||||
|
@ -520,8 +530,91 @@ uint32_t NativeBridgeGetVersion() {
|
|||
}
|
||||
|
||||
NativeBridgeSignalHandlerFn NativeBridgeGetSignalHandler(int signal) {
|
||||
if (NativeBridgeInitialized() && callbacks->version >= 2) {
|
||||
return callbacks->getSignalHandler(signal);
|
||||
if (NativeBridgeInitialized()) {
|
||||
if (isCompatibleWith(SIGNAL_VERSION)) {
|
||||
return callbacks->getSignalHandler(signal);
|
||||
} else {
|
||||
ALOGE("not compatible with version %d, cannot get signal handler", SIGNAL_VERSION);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int NativeBridgeUnloadLibrary(void* handle) {
|
||||
if (NativeBridgeInitialized()) {
|
||||
if (isCompatibleWith(NAMESPACE_VERSION)) {
|
||||
return callbacks->unloadLibrary(handle);
|
||||
} else {
|
||||
ALOGE("not compatible with version %d, cannot unload library", NAMESPACE_VERSION);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
char* NativeBridgeGetError() {
|
||||
if (NativeBridgeInitialized()) {
|
||||
if (isCompatibleWith(NAMESPACE_VERSION)) {
|
||||
return callbacks->getError();
|
||||
} else {
|
||||
ALOGE("not compatible with version %d, cannot get message", NAMESPACE_VERSION);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool NativeBridgeIsPathSupported(const char* path) {
|
||||
if (NativeBridgeInitialized()) {
|
||||
if (isCompatibleWith(NAMESPACE_VERSION)) {
|
||||
return callbacks->isPathSupported(path);
|
||||
} else {
|
||||
ALOGE("not compatible with version %d, cannot check via library path", NAMESPACE_VERSION);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NativeBridgeInitNamespace(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);
|
||||
} else {
|
||||
ALOGE("not compatible with version %d, cannot init namespace", NAMESPACE_VERSION);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
native_bridge_namespace_t* NativeBridgeCreateNamespace(const char* name,
|
||||
const char* ld_library_path,
|
||||
const char* default_library_path,
|
||||
uint64_t type,
|
||||
const char* permitted_when_isolated_path,
|
||||
native_bridge_namespace_t* parent_ns) {
|
||||
if (NativeBridgeInitialized()) {
|
||||
if (isCompatibleWith(NAMESPACE_VERSION)) {
|
||||
return callbacks->createNamespace(name,
|
||||
ld_library_path,
|
||||
default_library_path,
|
||||
type,
|
||||
permitted_when_isolated_path,
|
||||
parent_ns);
|
||||
} else {
|
||||
ALOGE("not compatible with version %d, cannot create namespace %s", NAMESPACE_VERSION, name);
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void* NativeBridgeLoadLibraryExt(const char* libpath, int flag, native_bridge_namespace_t* ns) {
|
||||
if (NativeBridgeInitialized()) {
|
||||
if (isCompatibleWith(NAMESPACE_VERSION)) {
|
||||
return callbacks->loadLibraryExt(libpath, flag, ns);
|
||||
} else {
|
||||
ALOGE("not compatible with version %d, cannot load library in namespace", NAMESPACE_VERSION);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -20,7 +20,13 @@ test_src_files := \
|
|||
PreInitializeNativeBridgeFail2_test.cpp \
|
||||
ReSetupNativeBridge_test.cpp \
|
||||
UnavailableNativeBridge_test.cpp \
|
||||
ValidNameNativeBridge_test.cpp
|
||||
ValidNameNativeBridge_test.cpp \
|
||||
NativeBridge3UnloadLibrary_test.cpp \
|
||||
NativeBridge3GetError_test.cpp \
|
||||
NativeBridge3IsPathSupported_test.cpp \
|
||||
NativeBridge3InitNamespace_test.cpp \
|
||||
NativeBridge3CreateNamespace_test.cpp \
|
||||
NativeBridge3LoadLibraryExt_test.cpp
|
||||
|
||||
|
||||
shared_libraries := \
|
||||
|
|
|
@ -68,3 +68,41 @@ LOCAL_LDFLAGS := -ldl
|
|||
LOCAL_MULTILIB := both
|
||||
|
||||
include $(BUILD_HOST_SHARED_LIBRARY)
|
||||
|
||||
|
||||
# v3.
|
||||
|
||||
NATIVE_BRIDGE3_COMMON_SRC_FILES := \
|
||||
DummyNativeBridge3.cpp
|
||||
|
||||
# Shared library for target
|
||||
# ========================================================
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE:= libnativebridge3-dummy
|
||||
|
||||
LOCAL_SRC_FILES:= $(NATIVE_BRIDGE3_COMMON_SRC_FILES)
|
||||
LOCAL_CLANG := true
|
||||
LOCAL_CFLAGS += -Werror -Wall
|
||||
LOCAL_CPPFLAGS := -std=gnu++11 -fvisibility=protected
|
||||
LOCAL_LDFLAGS := -ldl
|
||||
LOCAL_MULTILIB := both
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
# Shared library for host
|
||||
# ========================================================
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE:= libnativebridge3-dummy
|
||||
|
||||
LOCAL_SRC_FILES:= $(NATIVE_BRIDGE3_COMMON_SRC_FILES)
|
||||
LOCAL_CLANG := true
|
||||
LOCAL_CFLAGS += -Werror -Wall
|
||||
LOCAL_CPPFLAGS := -std=gnu++11 -fvisibility=protected
|
||||
LOCAL_LDFLAGS := -ldl
|
||||
LOCAL_MULTILIB := both
|
||||
|
||||
include $(BUILD_HOST_SHARED_LIBRARY)
|
||||
|
||||
|
||||
|
|
120
libnativebridge/tests/DummyNativeBridge3.cpp
Normal file
120
libnativebridge/tests/DummyNativeBridge3.cpp
Normal file
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// A dummy implementation of the native-bridge interface.
|
||||
|
||||
#include "nativebridge/native_bridge.h"
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
// NativeBridgeCallbacks implementations
|
||||
extern "C" bool native_bridge3_initialize(
|
||||
const android::NativeBridgeRuntimeCallbacks* /* art_cbs */,
|
||||
const char* /* app_code_cache_dir */,
|
||||
const char* /* isa */) {
|
||||
return true;
|
||||
}
|
||||
|
||||
extern "C" void* native_bridge3_loadLibrary(const char* /* libpath */, int /* flag */) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
extern "C" void* native_bridge3_getTrampoline(void* /* handle */, const char* /* name */,
|
||||
const char* /* shorty */, uint32_t /* len */) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
extern "C" bool native_bridge3_isSupported(const char* /* libpath */) {
|
||||
return false;
|
||||
}
|
||||
|
||||
extern "C" const struct android::NativeBridgeRuntimeValues* native_bridge3_getAppEnv(
|
||||
const char* /* abi */) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
extern "C" bool native_bridge3_isCompatibleWith(uint32_t version) {
|
||||
// For testing, allow 1-3, but disallow 4+.
|
||||
return version <= 3;
|
||||
}
|
||||
|
||||
static bool native_bridge3_dummy_signal_handler(int, siginfo_t*, void*) {
|
||||
// TODO: Implement something here. We'd either have to have a death test with a log here, or
|
||||
// we'd have to be able to resume after the faulting instruction...
|
||||
return true;
|
||||
}
|
||||
|
||||
extern "C" android::NativeBridgeSignalHandlerFn native_bridge3_getSignalHandler(int signal) {
|
||||
if (signal == SIGSEGV) {
|
||||
return &native_bridge3_dummy_signal_handler;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
extern "C" int native_bridge3_unloadLibrary(void* /* handle */) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" char* native_bridge3_getError() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
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 */) {
|
||||
return true;
|
||||
}
|
||||
|
||||
extern "C" android::native_bridge_namespace_t*
|
||||
native_bridge3_createNamespace(const char* /* name */,
|
||||
const char* /* ld_library_path */,
|
||||
const char* /* default_library_path */,
|
||||
uint64_t /* type */,
|
||||
const char* /* permitted_when_isolated_path */,
|
||||
android::native_bridge_namespace_t* /* parent_ns */) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
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
|
||||
};
|
||||
|
40
libnativebridge/tests/NativeBridge3CreateNamespace_test.cpp
Normal file
40
libnativebridge/tests/NativeBridge3CreateNamespace_test.cpp
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "NativeBridgeTest.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
constexpr const char* kNativeBridgeLibrary3 = "libnativebridge3-dummy.so";
|
||||
|
||||
TEST_F(NativeBridgeTest, V3_CreateNamespace) {
|
||||
// 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(nullptr, NativeBridgeCreateNamespace(nullptr, nullptr, nullptr,
|
||||
0, nullptr, nullptr));
|
||||
|
||||
// Clean-up code_cache
|
||||
ASSERT_EQ(0, rmdir(kCodeCache));
|
||||
}
|
||||
|
||||
} // namespace android
|
39
libnativebridge/tests/NativeBridge3GetError_test.cpp
Normal file
39
libnativebridge/tests/NativeBridge3GetError_test.cpp
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "NativeBridgeTest.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
constexpr const char* kNativeBridgeLibrary3 = "libnativebridge3-dummy.so";
|
||||
|
||||
TEST_F(NativeBridgeTest, V3_GetError) {
|
||||
// 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(nullptr, NativeBridgeGetError());
|
||||
|
||||
// Clean-up code_cache
|
||||
ASSERT_EQ(0, rmdir(kCodeCache));
|
||||
}
|
||||
|
||||
} // namespace android
|
39
libnativebridge/tests/NativeBridge3InitNamespace_test.cpp
Normal file
39
libnativebridge/tests/NativeBridge3InitNamespace_test.cpp
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "NativeBridgeTest.h"
|
||||
|
||||
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());
|
||||
|
||||
ASSERT_EQ(3U, NativeBridgeGetVersion());
|
||||
ASSERT_EQ(true, NativeBridgeInitNamespace(nullptr, nullptr));
|
||||
|
||||
// Clean-up code_cache
|
||||
ASSERT_EQ(0, rmdir(kCodeCache));
|
||||
}
|
||||
|
||||
} // namespace android
|
39
libnativebridge/tests/NativeBridge3IsPathSupported_test.cpp
Normal file
39
libnativebridge/tests/NativeBridge3IsPathSupported_test.cpp
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "NativeBridgeTest.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
constexpr const char* kNativeBridgeLibrary3 = "libnativebridge3-dummy.so";
|
||||
|
||||
TEST_F(NativeBridgeTest, V3_IsPathSupported) {
|
||||
// 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, NativeBridgeIsPathSupported(nullptr));
|
||||
|
||||
// Clean-up code_cache
|
||||
ASSERT_EQ(0, rmdir(kCodeCache));
|
||||
}
|
||||
|
||||
} // namespace android
|
39
libnativebridge/tests/NativeBridge3LoadLibraryExt_test.cpp
Normal file
39
libnativebridge/tests/NativeBridge3LoadLibraryExt_test.cpp
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "NativeBridgeTest.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
constexpr const char* kNativeBridgeLibrary3 = "libnativebridge3-dummy.so";
|
||||
|
||||
TEST_F(NativeBridgeTest, V3_LoadLibraryExt) {
|
||||
// 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(nullptr, NativeBridgeLoadLibraryExt(nullptr, 0, nullptr));
|
||||
|
||||
// Clean-up code_cache
|
||||
ASSERT_EQ(0, rmdir(kCodeCache));
|
||||
}
|
||||
|
||||
} // namespace android
|
39
libnativebridge/tests/NativeBridge3UnloadLibrary_test.cpp
Normal file
39
libnativebridge/tests/NativeBridge3UnloadLibrary_test.cpp
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "NativeBridgeTest.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
constexpr const char* kNativeBridgeLibrary3 = "libnativebridge3-dummy.so";
|
||||
|
||||
TEST_F(NativeBridgeTest, V3_UnloadLibrary) {
|
||||
// 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(0, NativeBridgeUnloadLibrary(nullptr));
|
||||
|
||||
// Clean-up code_cache
|
||||
ASSERT_EQ(0, rmdir(kCodeCache));
|
||||
}
|
||||
|
||||
} // namespace android
|
|
@ -25,6 +25,8 @@
|
|||
constexpr const char* kNativeBridgeLibrary = "libnativebridge-dummy.so";
|
||||
constexpr const char* kCodeCache = "./code_cache";
|
||||
constexpr const char* kCodeCacheStatFail = "./code_cache/temp";
|
||||
constexpr const char* kNativeBridgeLibrary2 = "libnativebridge2-dummy.so";
|
||||
constexpr const char* kNativeBridgeLibrary3 = "libnativebridge3-dummy.so";
|
||||
|
||||
namespace android {
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ cc_library {
|
|||
"libnativehelper",
|
||||
"liblog",
|
||||
"libcutils",
|
||||
"libnativebridge",
|
||||
],
|
||||
static_libs: ["libbase"],
|
||||
target: {
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include "jni.h"
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#if defined(__ANDROID__)
|
||||
#include <android/dlext.h>
|
||||
#endif
|
||||
|
@ -41,10 +42,12 @@ void* OpenNativeLibrary(JNIEnv* env,
|
|||
int32_t target_sdk_version,
|
||||
const char* path,
|
||||
jobject class_loader,
|
||||
jstring library_path);
|
||||
jstring library_path,
|
||||
bool* needs_native_bridge,
|
||||
std::string* error_msg);
|
||||
|
||||
__attribute__((visibility("default")))
|
||||
bool CloseNativeLibrary(void* handle);
|
||||
bool CloseNativeLibrary(void* handle, const bool needs_native_bridge);
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
// Look up linker namespace by class_loader. Returns nullptr if
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "android/log.h"
|
||||
#include "cutils/properties.h"
|
||||
#endif
|
||||
#include "nativebridge/native_bridge.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
@ -34,11 +35,53 @@
|
|||
#include <android-base/macros.h>
|
||||
#include <android-base/strings.h>
|
||||
|
||||
#define CHECK(predicate) LOG_ALWAYS_FATAL_IF(!(predicate),\
|
||||
"%s:%d: %s CHECK '" #predicate "' failed.",\
|
||||
__FILE__, __LINE__, __FUNCTION__)
|
||||
|
||||
namespace android {
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
static constexpr const char* kPublicNativeLibrariesSystemConfigPathFromRoot = "/etc/public.libraries.txt";
|
||||
static constexpr const char* kPublicNativeLibrariesVendorConfig = "/vendor/etc/public.libraries.txt";
|
||||
class NativeLoaderNamespace {
|
||||
public:
|
||||
NativeLoaderNamespace()
|
||||
: android_ns_(nullptr), native_bridge_ns_(nullptr) { }
|
||||
|
||||
explicit NativeLoaderNamespace(android_namespace_t* ns)
|
||||
: android_ns_(ns), native_bridge_ns_(nullptr) { }
|
||||
|
||||
explicit NativeLoaderNamespace(native_bridge_namespace_t* ns)
|
||||
: android_ns_(nullptr), native_bridge_ns_(ns) { }
|
||||
|
||||
NativeLoaderNamespace(NativeLoaderNamespace&& that) = default;
|
||||
NativeLoaderNamespace(const NativeLoaderNamespace& that) = default;
|
||||
|
||||
NativeLoaderNamespace& operator=(const NativeLoaderNamespace& that) = default;
|
||||
|
||||
android_namespace_t* get_android_ns() const {
|
||||
CHECK(native_bridge_ns_ == nullptr);
|
||||
return android_ns_;
|
||||
}
|
||||
|
||||
native_bridge_namespace_t* get_native_bridge_ns() const {
|
||||
CHECK(android_ns_ == nullptr);
|
||||
return native_bridge_ns_;
|
||||
}
|
||||
|
||||
bool is_android_namespace() const {
|
||||
return native_bridge_ns_ == nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
// Only one of them can be not null
|
||||
android_namespace_t* android_ns_;
|
||||
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";
|
||||
|
||||
// (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.
|
||||
|
@ -55,11 +98,13 @@ class LibraryNamespaces {
|
|||
public:
|
||||
LibraryNamespaces() : initialized_(false) { }
|
||||
|
||||
android_namespace_t* Create(JNIEnv* env,
|
||||
jobject class_loader,
|
||||
bool is_shared,
|
||||
jstring java_library_path,
|
||||
jstring java_permitted_path) {
|
||||
bool Create(JNIEnv* env,
|
||||
jobject class_loader,
|
||||
bool is_shared,
|
||||
jstring java_library_path,
|
||||
jstring java_permitted_path,
|
||||
NativeLoaderNamespace* ns,
|
||||
std::string* error_msg) {
|
||||
std::string library_path; // empty string by default.
|
||||
|
||||
if (java_library_path != nullptr) {
|
||||
|
@ -82,13 +127,13 @@ class LibraryNamespaces {
|
|||
}
|
||||
}
|
||||
|
||||
if (!initialized_ && !InitPublicNamespace(library_path.c_str())) {
|
||||
return nullptr;
|
||||
if (!initialized_ && !InitPublicNamespace(library_path.c_str(), error_msg)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
android_namespace_t* ns = FindNamespaceByClassLoader(env, class_loader);
|
||||
bool found = FindNamespaceByClassLoader(env, class_loader, nullptr);
|
||||
|
||||
LOG_ALWAYS_FATAL_IF(ns != nullptr,
|
||||
LOG_ALWAYS_FATAL_IF(found,
|
||||
"There is already a namespace associated with this classloader");
|
||||
|
||||
uint64_t namespace_type = ANDROID_NAMESPACE_TYPE_ISOLATED;
|
||||
|
@ -96,28 +141,66 @@ class LibraryNamespaces {
|
|||
namespace_type |= ANDROID_NAMESPACE_TYPE_SHARED;
|
||||
}
|
||||
|
||||
android_namespace_t* parent_ns = FindParentNamespaceByClassLoader(env, class_loader);
|
||||
NativeLoaderNamespace parent_ns;
|
||||
bool found_parent_namespace = FindParentNamespaceByClassLoader(env, class_loader, &parent_ns);
|
||||
|
||||
ns = android_create_namespace("classloader-namespace",
|
||||
nullptr,
|
||||
library_path.c_str(),
|
||||
namespace_type,
|
||||
permitted_path.c_str(),
|
||||
parent_ns);
|
||||
bool is_native_bridge = false;
|
||||
|
||||
if (ns != nullptr) {
|
||||
namespaces_.push_back(std::make_pair(env->NewWeakGlobalRef(class_loader), ns));
|
||||
if (found_parent_namespace) {
|
||||
is_native_bridge = !parent_ns.is_android_namespace();
|
||||
} else if (!library_path.empty()) {
|
||||
is_native_bridge = NativeBridgeIsPathSupported(library_path.c_str());
|
||||
}
|
||||
|
||||
return ns;
|
||||
NativeLoaderNamespace native_loader_ns;
|
||||
if (!is_native_bridge) {
|
||||
android_namespace_t* ns = android_create_namespace("classloader-namespace",
|
||||
nullptr,
|
||||
library_path.c_str(),
|
||||
namespace_type,
|
||||
permitted_path.c_str(),
|
||||
parent_ns.get_android_ns());
|
||||
if (ns == nullptr) {
|
||||
*error_msg = dlerror();
|
||||
return false;
|
||||
}
|
||||
|
||||
native_loader_ns = NativeLoaderNamespace(ns);
|
||||
} else {
|
||||
native_bridge_namespace_t* ns = NativeBridgeCreateNamespace("classloader-namespace",
|
||||
nullptr,
|
||||
library_path.c_str(),
|
||||
namespace_type,
|
||||
permitted_path.c_str(),
|
||||
parent_ns.get_native_bridge_ns());
|
||||
if (ns == nullptr) {
|
||||
*error_msg = NativeBridgeGetError();
|
||||
return false;
|
||||
}
|
||||
|
||||
native_loader_ns = NativeLoaderNamespace(ns);
|
||||
}
|
||||
|
||||
namespaces_.push_back(std::make_pair(env->NewWeakGlobalRef(class_loader), native_loader_ns));
|
||||
|
||||
*ns = native_loader_ns;
|
||||
return true;
|
||||
}
|
||||
|
||||
android_namespace_t* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
|
||||
bool FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader, NativeLoaderNamespace* ns) {
|
||||
auto it = std::find_if(namespaces_.begin(), namespaces_.end(),
|
||||
[&](const std::pair<jweak, android_namespace_t*>& value) {
|
||||
[&](const std::pair<jweak, NativeLoaderNamespace>& value) {
|
||||
return env->IsSameObject(value.first, class_loader);
|
||||
});
|
||||
return it != namespaces_.end() ? it->second : nullptr;
|
||||
if (it != namespaces_.end()) {
|
||||
if (ns != nullptr) {
|
||||
*ns = it->second;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Initialize() {
|
||||
|
@ -217,12 +300,25 @@ class LibraryNamespaces {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool InitPublicNamespace(const char* library_path) {
|
||||
bool InitPublicNamespace(const char* library_path, std::string* error_msg) {
|
||||
// Ask native bride if this apps library path should be handled by it
|
||||
bool is_native_bridge = NativeBridgeIsPathSupported(library_path);
|
||||
|
||||
// (http://b/25844435) - Some apps call dlopen from generated code (mono jited
|
||||
// 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_namespaces(public_libraries_.c_str(), library_path);
|
||||
if (!is_native_bridge) {
|
||||
initialized_ = android_init_namespaces(public_libraries_.c_str(), library_path);
|
||||
if (!initialized_) {
|
||||
*error_msg = dlerror();
|
||||
}
|
||||
} else {
|
||||
initialized_ = NativeBridgeInitNamespace(public_libraries_.c_str(), library_path);
|
||||
if (!initialized_) {
|
||||
*error_msg = NativeBridgeGetError();
|
||||
}
|
||||
}
|
||||
|
||||
return initialized_;
|
||||
}
|
||||
|
@ -236,22 +332,24 @@ class LibraryNamespaces {
|
|||
return env->CallObjectMethod(class_loader, get_parent);
|
||||
}
|
||||
|
||||
android_namespace_t* FindParentNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
|
||||
bool FindParentNamespaceByClassLoader(JNIEnv* env,
|
||||
jobject class_loader,
|
||||
NativeLoaderNamespace* ns) {
|
||||
jobject parent_class_loader = GetParentClassLoader(env, class_loader);
|
||||
|
||||
while (parent_class_loader != nullptr) {
|
||||
android_namespace_t* ns = FindNamespaceByClassLoader(env, parent_class_loader);
|
||||
if (ns != nullptr) {
|
||||
return ns;
|
||||
if (FindNamespaceByClassLoader(env, parent_class_loader, ns)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
parent_class_loader = GetParentClassLoader(env, parent_class_loader);
|
||||
}
|
||||
return nullptr;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool initialized_;
|
||||
std::vector<std::pair<jweak, android_namespace_t*>> namespaces_;
|
||||
std::vector<std::pair<jweak, NativeLoaderNamespace>> namespaces_;
|
||||
std::string public_libraries_;
|
||||
|
||||
|
||||
|
@ -285,13 +383,18 @@ jstring CreateClassLoaderNamespace(JNIEnv* env,
|
|||
#if defined(__ANDROID__)
|
||||
UNUSED(target_sdk_version);
|
||||
std::lock_guard<std::mutex> guard(g_namespaces_mutex);
|
||||
android_namespace_t* ns = g_namespaces->Create(env,
|
||||
class_loader,
|
||||
is_shared,
|
||||
library_path,
|
||||
permitted_path);
|
||||
if (ns == nullptr) {
|
||||
return env->NewStringUTF(dlerror());
|
||||
|
||||
std::string error_msg;
|
||||
NativeLoaderNamespace ns;
|
||||
bool success = g_namespaces->Create(env,
|
||||
class_loader,
|
||||
is_shared,
|
||||
library_path,
|
||||
permitted_path,
|
||||
&ns,
|
||||
&error_msg);
|
||||
if (!success) {
|
||||
return env->NewStringUTF(error_msg.c_str());
|
||||
}
|
||||
#else
|
||||
UNUSED(env, target_sdk_version, class_loader, is_shared,
|
||||
|
@ -304,44 +407,83 @@ void* OpenNativeLibrary(JNIEnv* env,
|
|||
int32_t target_sdk_version,
|
||||
const char* path,
|
||||
jobject class_loader,
|
||||
jstring library_path) {
|
||||
jstring library_path,
|
||||
bool* needs_native_bridge,
|
||||
std::string* error_msg) {
|
||||
#if defined(__ANDROID__)
|
||||
UNUSED(target_sdk_version);
|
||||
if (class_loader == nullptr) {
|
||||
*needs_native_bridge = false;
|
||||
return dlopen(path, RTLD_NOW);
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> guard(g_namespaces_mutex);
|
||||
android_namespace_t* ns = g_namespaces->FindNamespaceByClassLoader(env, class_loader);
|
||||
NativeLoaderNamespace ns;
|
||||
|
||||
if (ns == nullptr) {
|
||||
if (!g_namespaces->FindNamespaceByClassLoader(env, class_loader, &ns)) {
|
||||
// This is the case where the classloader was not created by ApplicationLoaders
|
||||
// In this case we create an isolated not-shared namespace for it.
|
||||
ns = g_namespaces->Create(env, class_loader, false, library_path, nullptr);
|
||||
if (ns == nullptr) {
|
||||
if (!g_namespaces->Create(env, class_loader, false, library_path, nullptr, &ns, error_msg)) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
android_dlextinfo extinfo;
|
||||
extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
|
||||
extinfo.library_namespace = ns;
|
||||
if (ns.is_android_namespace()) {
|
||||
android_dlextinfo extinfo;
|
||||
extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
|
||||
extinfo.library_namespace = ns.get_android_ns();
|
||||
|
||||
return android_dlopen_ext(path, RTLD_NOW, &extinfo);
|
||||
void* handle = android_dlopen_ext(path, RTLD_NOW, &extinfo);
|
||||
if (handle == nullptr) {
|
||||
*error_msg = dlerror();
|
||||
}
|
||||
*needs_native_bridge = false;
|
||||
return handle;
|
||||
} else {
|
||||
void* handle = NativeBridgeLoadLibraryExt(path, RTLD_NOW, ns.get_native_bridge_ns());
|
||||
if (handle == nullptr) {
|
||||
*error_msg = NativeBridgeGetError();
|
||||
}
|
||||
*needs_native_bridge = true;
|
||||
return handle;
|
||||
}
|
||||
#else
|
||||
UNUSED(env, target_sdk_version, class_loader, library_path);
|
||||
return dlopen(path, RTLD_NOW);
|
||||
*needs_native_bridge = false;
|
||||
void* handle = dlopen(path, RTLD_NOW);
|
||||
if (handle == nullptr) {
|
||||
if (NativeBridgeIsSupported(path)) {
|
||||
*needs_native_bridge = true;
|
||||
handle = NativeBridgeLoadLibrary(path, RTLD_NOW);
|
||||
if (handle == nullptr) {
|
||||
*error_msg = NativeBridgeGetError();
|
||||
}
|
||||
} else {
|
||||
*needs_native_bridge = false;
|
||||
*error_msg = dlerror();
|
||||
}
|
||||
}
|
||||
return handle;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool CloseNativeLibrary(void* handle) {
|
||||
return dlclose(handle) == 0;
|
||||
bool CloseNativeLibrary(void* handle, const bool needs_native_bridge) {
|
||||
return needs_native_bridge ? NativeBridgeUnloadLibrary(handle) :
|
||||
dlclose(handle);
|
||||
}
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
android_namespace_t* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
|
||||
std::lock_guard<std::mutex> guard(g_namespaces_mutex);
|
||||
return g_namespaces->FindNamespaceByClassLoader(env, class_loader);
|
||||
// native_bridge_namespaces are not supported for callers of this function.
|
||||
// At the moment this is libwebviewchromium_loader and vulkan.
|
||||
NativeLoaderNamespace ns;
|
||||
if (g_namespaces->FindNamespaceByClassLoader(env, class_loader, &ns)) {
|
||||
CHECK(ns.is_android_namespace());
|
||||
return ns.get_android_ns();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
Loading…
Reference in a new issue