Don't create anonymous namespace
Don't create anonymous namespace separately, use the first namespace that is created for app classloader as the anonymous namespace. Note that the anonymous namespace is set via the new ANDROID_NAMESPACE_TYPE_ALSO_USED_AS_ANONYMOUS. I didn't creat a new function like android_set_anonymous_namespace as it requires uprev of the libnativebridge interface and makes it harder to delete the old android_init_anonymous_namespace as we have to keep it until all proprietary bridged loaders are updated. Bug: 130388701 Test: CtsBionicTestCases Test: run games on http://www.monogame.net/showcase/?Android Change-Id: I0fdd614365eaa56c4ab47538bf3772d94bd9ae55
This commit is contained in:
parent
e2adc14803
commit
b37c4818da
6 changed files with 72 additions and 75 deletions
|
@ -22,18 +22,6 @@
|
|||
|
||||
__BEGIN_DECLS
|
||||
|
||||
/*
|
||||
* Initializes anonymous namespaces. The shared_libs_sonames is the list of sonames
|
||||
* to be shared by default namespace separated by colon. Example: "libc.so:libm.so:libdl.so".
|
||||
*
|
||||
* The library_search_path is the search path for anonymous namespace. The anonymous namespace
|
||||
* is used in the case when linker cannot identify the caller of dlopen/dlsym. This happens
|
||||
* for the code not loaded by dynamic linker; for example calls from the mono-compiled code.
|
||||
*/
|
||||
extern bool android_init_anonymous_namespace(const char* shared_libs_sonames,
|
||||
const char* library_search_path);
|
||||
|
||||
|
||||
enum {
|
||||
/* A regular namespace is the namespace with a custom search path that does
|
||||
* not impose any restrictions on the location of native libraries.
|
||||
|
@ -62,8 +50,18 @@ enum {
|
|||
*/
|
||||
ANDROID_NAMESPACE_TYPE_GREYLIST_ENABLED = 0x08000000,
|
||||
|
||||
ANDROID_NAMESPACE_TYPE_SHARED_ISOLATED = ANDROID_NAMESPACE_TYPE_SHARED |
|
||||
ANDROID_NAMESPACE_TYPE_ISOLATED,
|
||||
/* This flag instructs linker to use this namespace as the anonymous
|
||||
* namespace. The anonymous namespace is used in the case when linker cannot
|
||||
* identify the caller of dlopen/dlsym. This happens for the code not loaded
|
||||
* by dynamic linker; for example calls from the mono-compiled code. There can
|
||||
* be only one anonymous namespace in a process. If there already is an
|
||||
* anonymous namespace in the process, using this flag when creating a new
|
||||
* namespace causes an error.
|
||||
*/
|
||||
ANDROID_NAMESPACE_TYPE_ALSO_USED_AS_ANONYMOUS = 0x10000000,
|
||||
|
||||
ANDROID_NAMESPACE_TYPE_SHARED_ISOLATED =
|
||||
ANDROID_NAMESPACE_TYPE_SHARED | ANDROID_NAMESPACE_TYPE_ISOLATED,
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -159,13 +159,6 @@ Result<NativeLoaderNamespace*> LibraryNamespaces::Create(JNIEnv* env, uint32_t t
|
|||
}
|
||||
}
|
||||
|
||||
// Initialize the anonymous namespace with the first non-empty library path.
|
||||
Result<void> ret;
|
||||
if (!library_path.empty() && !initialized_ &&
|
||||
!(ret = InitPublicNamespace(library_path.c_str()))) {
|
||||
return ret.error();
|
||||
}
|
||||
|
||||
LOG_ALWAYS_FATAL_IF(FindNamespaceByClassLoader(env, class_loader) != nullptr,
|
||||
"There is already a namespace associated with this classloader");
|
||||
|
||||
|
@ -215,13 +208,22 @@ Result<NativeLoaderNamespace*> LibraryNamespaces::Create(JNIEnv* env, uint32_t t
|
|||
|
||||
// Create the app namespace
|
||||
NativeLoaderNamespace* parent_ns = FindParentNamespaceByClassLoader(env, class_loader);
|
||||
auto app_ns =
|
||||
NativeLoaderNamespace::Create(namespace_name, library_path, permitted_path, parent_ns,
|
||||
is_shared, target_sdk_version < 24 /* is_greylist_enabled */);
|
||||
// Heuristic: the first classloader with non-empty library_path is assumed to
|
||||
// be the main classloader for app
|
||||
// TODO(b/139178525) remove this heuristic by determining this in LoadedApk (or its
|
||||
// friends) and then passing it down to here.
|
||||
bool is_main_classloader = app_main_namespace_ == nullptr && !library_path.empty();
|
||||
// Policy: the namespace for the main classloader is also used as the
|
||||
// anonymous namespace.
|
||||
bool also_used_as_anonymous = is_main_classloader;
|
||||
// Note: this function is executed with g_namespaces_mutex held, thus no
|
||||
// racing here.
|
||||
auto app_ns = NativeLoaderNamespace::Create(
|
||||
namespace_name, library_path, permitted_path, parent_ns, is_shared,
|
||||
target_sdk_version < 24 /* is_greylist_enabled */, also_used_as_anonymous);
|
||||
if (!app_ns) {
|
||||
return app_ns.error();
|
||||
}
|
||||
|
||||
// ... and link to other namespaces to allow access to some public libraries
|
||||
bool is_bridged = app_ns->IsBridged();
|
||||
|
||||
|
@ -278,6 +280,9 @@ Result<NativeLoaderNamespace*> LibraryNamespaces::Create(JNIEnv* env, uint32_t t
|
|||
}
|
||||
|
||||
namespaces_.push_back(std::make_pair(env->NewWeakGlobalRef(class_loader), *app_ns));
|
||||
if (is_main_classloader) {
|
||||
app_main_namespace_ = &(*app_ns);
|
||||
}
|
||||
|
||||
return &(namespaces_.back().second);
|
||||
}
|
||||
|
@ -295,32 +300,6 @@ NativeLoaderNamespace* LibraryNamespaces::FindNamespaceByClassLoader(JNIEnv* env
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
Result<void> LibraryNamespaces::InitPublicNamespace(const char* library_path) {
|
||||
// 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_anonymous_namespace(default_public_libraries().c_str(),
|
||||
is_native_bridge ? nullptr : library_path);
|
||||
if (!initialized_) {
|
||||
return Error() << dlerror();
|
||||
}
|
||||
|
||||
// and now initialize native bridge namespaces if necessary.
|
||||
if (NativeBridgeInitialized()) {
|
||||
initialized_ = NativeBridgeInitAnonymousNamespace(default_public_libraries().c_str(),
|
||||
is_native_bridge ? library_path : nullptr);
|
||||
if (!initialized_) {
|
||||
return Error() << NativeBridgeGetError();
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
NativeLoaderNamespace* LibraryNamespaces::FindParentNamespaceByClassLoader(JNIEnv* env,
|
||||
jobject class_loader) {
|
||||
jobject parent_class_loader = GetParentClassLoader(env, class_loader);
|
||||
|
|
|
@ -48,6 +48,7 @@ class LibraryNamespaces {
|
|||
void Reset() {
|
||||
namespaces_.clear();
|
||||
initialized_ = false;
|
||||
app_main_namespace_ = nullptr;
|
||||
}
|
||||
Result<NativeLoaderNamespace*> Create(JNIEnv* env, uint32_t target_sdk_version,
|
||||
jobject class_loader, bool is_shared, jstring dex_path,
|
||||
|
@ -59,6 +60,7 @@ class LibraryNamespaces {
|
|||
NativeLoaderNamespace* FindParentNamespaceByClassLoader(JNIEnv* env, jobject class_loader);
|
||||
|
||||
bool initialized_;
|
||||
NativeLoaderNamespace* app_main_namespace_;
|
||||
std::list<std::pair<jweak, NativeLoaderNamespace>> namespaces_;
|
||||
};
|
||||
|
||||
|
|
|
@ -85,7 +85,8 @@ Result<NativeLoaderNamespace> NativeLoaderNamespace::GetPlatformNamespace(bool i
|
|||
|
||||
Result<NativeLoaderNamespace> NativeLoaderNamespace::Create(
|
||||
const std::string& name, const std::string& search_paths, const std::string& permitted_paths,
|
||||
const NativeLoaderNamespace* parent, bool is_shared, bool is_greylist_enabled) {
|
||||
const NativeLoaderNamespace* parent, bool is_shared, bool is_greylist_enabled,
|
||||
bool also_used_as_anonymous) {
|
||||
bool is_bridged = false;
|
||||
if (parent != nullptr) {
|
||||
is_bridged = parent->IsBridged();
|
||||
|
@ -100,7 +101,17 @@ Result<NativeLoaderNamespace> NativeLoaderNamespace::Create(
|
|||
}
|
||||
const NativeLoaderNamespace& effective_parent = parent != nullptr ? *parent : *platform_ns;
|
||||
|
||||
// All namespaces for apps are isolated
|
||||
uint64_t type = ANDROID_NAMESPACE_TYPE_ISOLATED;
|
||||
|
||||
// The namespace is also used as the anonymous namespace
|
||||
// which is used when the linker fails to determine the caller address
|
||||
if (also_used_as_anonymous) {
|
||||
type |= ANDROID_NAMESPACE_TYPE_ALSO_USED_AS_ANONYMOUS;
|
||||
}
|
||||
|
||||
// Bundled apps have access to all system libraries that are currently loaded
|
||||
// in the default namespace
|
||||
if (is_shared) {
|
||||
type |= ANDROID_NAMESPACE_TYPE_SHARED;
|
||||
}
|
||||
|
|
|
@ -39,7 +39,8 @@ struct NativeLoaderNamespace {
|
|||
const std::string& search_paths,
|
||||
const std::string& permitted_paths,
|
||||
const NativeLoaderNamespace* parent, bool is_shared,
|
||||
bool is_greylist_enabled);
|
||||
bool is_greylist_enabled,
|
||||
bool also_used_as_anonymous);
|
||||
|
||||
NativeLoaderNamespace(NativeLoaderNamespace&&) = default;
|
||||
NativeLoaderNamespace(const NativeLoaderNamespace&) = default;
|
||||
|
|
|
@ -331,7 +331,8 @@ class NativeLoaderTest_Create : public NativeLoaderTest {
|
|||
|
||||
// expected output (.. for the default test inputs)
|
||||
std::string expected_namespace_name = "classloader-namespace";
|
||||
uint64_t expected_namespace_flags = ANDROID_NAMESPACE_TYPE_ISOLATED;
|
||||
uint64_t expected_namespace_flags =
|
||||
ANDROID_NAMESPACE_TYPE_ISOLATED | ANDROID_NAMESPACE_TYPE_ALSO_USED_AS_ANONYMOUS;
|
||||
std::string expected_library_path = library_path;
|
||||
std::string expected_permitted_path = std::string("/data:/mnt/expand:") + permitted_path;
|
||||
std::string expected_parent_namespace = "platform";
|
||||
|
@ -356,17 +357,6 @@ class NativeLoaderTest_Create : public NativeLoaderTest {
|
|||
EXPECT_CALL(*mock, NativeBridgeIsPathSupported(_)).Times(AnyNumber());
|
||||
EXPECT_CALL(*mock, NativeBridgeInitialized()).Times(AnyNumber());
|
||||
|
||||
if (IsBridged()) {
|
||||
EXPECT_CALL(*mock,
|
||||
mock_init_anonymous_namespace(false, StrEq(default_public_libraries()), nullptr))
|
||||
.WillOnce(Return(true));
|
||||
|
||||
EXPECT_CALL(*mock, NativeBridgeInitialized()).WillOnce(Return(true));
|
||||
}
|
||||
|
||||
EXPECT_CALL(*mock, mock_init_anonymous_namespace(
|
||||
Eq(IsBridged()), StrEq(default_public_libraries()), StrEq(library_path)))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(*mock, mock_create_namespace(
|
||||
Eq(IsBridged()), StrEq(expected_namespace_name), nullptr,
|
||||
StrEq(expected_library_path), expected_namespace_flags,
|
||||
|
@ -443,7 +433,7 @@ TEST_P(NativeLoaderTest_Create, BundledSystemApp) {
|
|||
dex_path = "/system/app/foo/foo.apk";
|
||||
is_shared = true;
|
||||
|
||||
expected_namespace_flags = ANDROID_NAMESPACE_TYPE_ISOLATED | ANDROID_NAMESPACE_TYPE_SHARED;
|
||||
expected_namespace_flags |= ANDROID_NAMESPACE_TYPE_SHARED;
|
||||
SetExpectations();
|
||||
RunTest();
|
||||
}
|
||||
|
@ -452,7 +442,7 @@ TEST_P(NativeLoaderTest_Create, BundledVendorApp) {
|
|||
dex_path = "/vendor/app/foo/foo.apk";
|
||||
is_shared = true;
|
||||
|
||||
expected_namespace_flags = ANDROID_NAMESPACE_TYPE_ISOLATED | ANDROID_NAMESPACE_TYPE_SHARED;
|
||||
expected_namespace_flags |= ANDROID_NAMESPACE_TYPE_SHARED;
|
||||
SetExpectations();
|
||||
RunTest();
|
||||
}
|
||||
|
@ -475,7 +465,7 @@ TEST_P(NativeLoaderTest_Create, BundledProductApp_pre30) {
|
|||
dex_path = "/product/app/foo/foo.apk";
|
||||
is_shared = true;
|
||||
|
||||
expected_namespace_flags = ANDROID_NAMESPACE_TYPE_ISOLATED | ANDROID_NAMESPACE_TYPE_SHARED;
|
||||
expected_namespace_flags |= ANDROID_NAMESPACE_TYPE_SHARED;
|
||||
SetExpectations();
|
||||
RunTest();
|
||||
}
|
||||
|
@ -485,7 +475,7 @@ TEST_P(NativeLoaderTest_Create, BundledProductApp_post30) {
|
|||
is_shared = true;
|
||||
target_sdk_version = 30;
|
||||
|
||||
expected_namespace_flags = ANDROID_NAMESPACE_TYPE_ISOLATED | ANDROID_NAMESPACE_TYPE_SHARED;
|
||||
expected_namespace_flags |= ANDROID_NAMESPACE_TYPE_SHARED;
|
||||
SetExpectations();
|
||||
RunTest();
|
||||
}
|
||||
|
@ -512,6 +502,22 @@ TEST_P(NativeLoaderTest_Create, UnbundledProductApp_post30) {
|
|||
RunTest();
|
||||
}
|
||||
|
||||
TEST_P(NativeLoaderTest_Create, NamespaceForSharedLibIsNotUsedAsAnonymousNamespace) {
|
||||
if (IsBridged()) {
|
||||
// There is no shared lib in translated arch
|
||||
// TODO(jiyong): revisit this
|
||||
return;
|
||||
}
|
||||
// compared to apks, for java shared libs, library_path is empty; java shared
|
||||
// libs don't have their own native libs. They use platform's.
|
||||
library_path = "";
|
||||
expected_library_path = library_path;
|
||||
// no ALSO_USED_AS_ANONYMOUS
|
||||
expected_namespace_flags = ANDROID_NAMESPACE_TYPE_ISOLATED;
|
||||
SetExpectations();
|
||||
RunTest();
|
||||
}
|
||||
|
||||
TEST_P(NativeLoaderTest_Create, TwoApks) {
|
||||
SetExpectations();
|
||||
const uint32_t second_app_target_sdk_version = 29;
|
||||
|
@ -523,6 +529,8 @@ TEST_P(NativeLoaderTest_Create, TwoApks) {
|
|||
const std::string expected_second_app_permitted_path =
|
||||
std::string("/data:/mnt/expand:") + second_app_permitted_path;
|
||||
const std::string expected_second_app_parent_namespace = "classloader-namespace";
|
||||
// no ALSO_USED_AS_ANONYMOUS
|
||||
const uint64_t expected_second_namespace_flags = ANDROID_NAMESPACE_TYPE_ISOLATED;
|
||||
|
||||
// The scenario is that second app is loaded by the first app.
|
||||
// So the first app's classloader (`classloader`) is parent of the second
|
||||
|
@ -532,10 +540,10 @@ TEST_P(NativeLoaderTest_Create, TwoApks) {
|
|||
|
||||
// namespace for the second app is created. Its parent is set to the namespace
|
||||
// of the first app.
|
||||
EXPECT_CALL(*mock, mock_create_namespace(Eq(IsBridged()), StrEq(expected_namespace_name), nullptr,
|
||||
StrEq(second_app_library_path), expected_namespace_flags,
|
||||
StrEq(expected_second_app_permitted_path),
|
||||
NsEq(dex_path.c_str())))
|
||||
EXPECT_CALL(*mock, mock_create_namespace(
|
||||
Eq(IsBridged()), StrEq(expected_namespace_name), nullptr,
|
||||
StrEq(second_app_library_path), expected_second_namespace_flags,
|
||||
StrEq(expected_second_app_permitted_path), NsEq(dex_path.c_str())))
|
||||
.WillOnce(Return(TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE(second_app_dex_path.c_str()))));
|
||||
EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), NsEq(second_app_dex_path.c_str()), _, _))
|
||||
.WillRepeatedly(Return(true));
|
||||
|
@ -568,7 +576,5 @@ TEST_P(NativeLoaderTest_Create, TwoApks) {
|
|||
|
||||
INSTANTIATE_TEST_SUITE_P(NativeLoaderTests_Create, NativeLoaderTest_Create, testing::Bool());
|
||||
|
||||
// TODO(b/130388701#comment22) add a test for anonymous namespace
|
||||
|
||||
} // namespace nativeloader
|
||||
} // namespace android
|
||||
|
|
Loading…
Reference in a new issue