Merge "Fix SYSCALLS.TXT now clock_getres comes from the vdso."
diff --git a/libc/Android.bp b/libc/Android.bp
index 3ec75ee..a02139a 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -2036,6 +2036,7 @@
license: "NOTICE",
}
+// Not actually used in the NDK, but needed to build AOSP for mips.
ndk_headers {
name: "libc_asm_mips",
from: "kernel/uapi/asm-mips",
@@ -2044,6 +2045,7 @@
license: "NOTICE",
}
+// Not actually used in the NDK, but needed to build AOSP for mips64.
ndk_headers {
name: "libc_asm_mips64",
from: "kernel/uapi/asm-mips",
diff --git a/linker/linker.cpp b/linker/linker.cpp
index abfd00f..4ad44fa 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -328,9 +328,7 @@
TRACE("name %s: freeing soinfo @ %p", si->get_realpath(), si);
if (!solist_remove_soinfo(si)) {
- // TODO (dimitry): revisit this - for now preserving the logic
- // but it does not look right, abort if soinfo is not in the list instead?
- return;
+ async_safe_fatal("soinfo=%p is not in soinfo_list (double unload?)", si);
}
// clear links to/from si
@@ -718,13 +716,11 @@
// walk_dependencies_tree returns false if walk was terminated
// by the action and true otherwise.
template<typename F>
-static bool walk_dependencies_tree(soinfo* root_soinfos[], size_t root_soinfos_size, F action) {
+static bool walk_dependencies_tree(soinfo* root_soinfo, F action) {
SoinfoLinkedList visit_list;
SoinfoLinkedList visited;
- for (size_t i = 0; i < root_soinfos_size; ++i) {
- visit_list.push_back(root_soinfos[i]);
- }
+ visit_list.push_back(root_soinfo);
soinfo* si;
while ((si = visit_list.pop_front()) != nullptr) {
@@ -760,7 +756,7 @@
const ElfW(Sym)* result = nullptr;
bool skip_lookup = skip_until != nullptr;
- walk_dependencies_tree(&root, 1, [&](soinfo* current_soinfo) {
+ walk_dependencies_tree(root, [&](soinfo* current_soinfo) {
if (skip_lookup) {
skip_lookup = current_soinfo != skip_until;
return kWalkContinue;
@@ -1478,7 +1474,6 @@
if (load_library(linked_namespace.linked_namespace(), task, zip_archive_cache, load_tasks, rtld_flags, false)) {
return true;
}
- // lib was not found in the namespace. Try next linked namespace.
} else {
// lib is already loaded
return true;
@@ -1491,7 +1486,6 @@
}
static void soinfo_unload(soinfo* si);
-static void soinfo_unload(soinfo* soinfos[], size_t count);
static void shuffle(std::vector<LoadTask*>* v) {
for (size_t i = 0, size = v->size(); i < size; ++i) {
@@ -1516,9 +1510,9 @@
const android_dlextinfo* extinfo,
bool add_as_children,
bool search_linked_namespaces,
- std::unordered_map<const soinfo*, ElfReader>& readers_map,
std::vector<android_namespace_t*>* namespaces) {
// Step 0: prepare.
+ std::unordered_map<const soinfo*, ElfReader> readers_map;
LoadTaskList load_tasks;
for (size_t i = 0; i < library_names_count; ++i) {
@@ -1548,11 +1542,6 @@
}
});
- auto failure_guard = android::base::make_scope_guard([&]() {
- // Housekeeping
- soinfo_unload(soinfos, soinfos_count);
- });
-
ZipArchiveCache zip_archive_cache;
// Step 1: expand the list of load_tasks to include
@@ -1565,7 +1554,6 @@
task->set_extinfo(is_dt_needed ? nullptr : extinfo);
task->set_dt_needed(is_dt_needed);
- // try to find the load.
// Note: start from the namespace that is stored in the LoadTask. This namespace
// is different from the current namespace when the LoadTask is for a transitive
// dependency and the lib that created the LoadTask is not found in the
@@ -1583,10 +1571,6 @@
if (is_dt_needed) {
needed_by->add_child(si);
-
- if (si->is_linked()) {
- si->increment_ref_count();
- }
}
// When ld_preloads is not null, the first
@@ -1662,77 +1646,116 @@
}
}
- // Step 5: link libraries that are not destined to this namespace.
- // Do this by recursively calling find_libraries on the namespace where the lib
- // was found during Step 1.
+ // Step 5: Collect roots of local_groups.
+ // Whenever needed_by->si link crosses a namespace boundary it forms its own local_group.
+ // Here we collect new roots to link them separately later on. Note that we need to avoid
+ // collecting duplicates. Also the order is important. They need to be linked in the same
+ // BFS order we link individual libraries.
+ std::vector<soinfo*> local_group_roots;
+ if (start_with != nullptr && add_as_children) {
+ local_group_roots.push_back(start_with);
+ } else {
+ CHECK(soinfos_count == 1);
+ local_group_roots.push_back(soinfos[0]);
+ }
+
for (auto&& task : load_tasks) {
soinfo* si = task->get_soinfo();
- if (si->get_primary_namespace() != ns) {
- const char* name = task->get_name();
- if (find_libraries(si->get_primary_namespace(), task->get_needed_by(), &name, 1,
- nullptr /* soinfos */, nullptr /* ld_preloads */, 0 /* ld_preload_count */,
- rtld_flags, nullptr /* extinfo */, false /* add_as_children */,
- false /* search_linked_namespaces */, readers_map, namespaces)) {
- // If this lib is directly needed by one of the libs in this namespace,
- // then increment the count
- soinfo* needed_by = task->get_needed_by();
- if (needed_by != nullptr && needed_by->get_primary_namespace() == ns && si->is_linked()) {
- si->increment_ref_count();
- }
- } else {
- return false;
+ soinfo* needed_by = task->get_needed_by();
+ bool is_dt_needed = needed_by != nullptr && (needed_by != start_with || add_as_children);
+ android_namespace_t* needed_by_ns =
+ is_dt_needed ? needed_by->get_primary_namespace() : ns;
+
+ if (!si->is_linked() && si->get_primary_namespace() != needed_by_ns) {
+ auto it = std::find(local_group_roots.begin(), local_group_roots.end(), si);
+ LD_LOG(kLogDlopen,
+ "Crossing namespace boundary (si=%s@%p, si_ns=%s@%p, needed_by=%s@%p, ns=%s@%p, needed_by_ns=%s@%p) adding to local_group_roots: %s",
+ si->get_realpath(),
+ si,
+ si->get_primary_namespace()->get_name(),
+ si->get_primary_namespace(),
+ needed_by == nullptr ? "(nullptr)" : needed_by->get_realpath(),
+ needed_by,
+ ns->get_name(),
+ ns,
+ needed_by_ns->get_name(),
+ needed_by_ns,
+ it == local_group_roots.end() ? "yes" : "no");
+
+ if (it == local_group_roots.end()) {
+ local_group_roots.push_back(si);
}
}
}
- // Step 6: link libraries in this namespace
- soinfo_list_t local_group;
- walk_dependencies_tree(
- (start_with != nullptr && add_as_children) ? &start_with : soinfos,
- (start_with != nullptr && add_as_children) ? 1 : soinfos_count,
+ // Step 6: Link all local groups
+ for (auto root : local_group_roots) {
+ soinfo_list_t local_group;
+ android_namespace_t* local_group_ns = root->get_primary_namespace();
+
+ walk_dependencies_tree(root,
[&] (soinfo* si) {
- if (ns->is_accessible(si)) {
- local_group.push_back(si);
- return kWalkContinue;
- } else {
- return kWalkSkip;
- }
- });
+ if (local_group_ns->is_accessible(si)) {
+ local_group.push_back(si);
+ return kWalkContinue;
+ } else {
+ return kWalkSkip;
+ }
+ });
- soinfo_list_t global_group = ns->get_global_group();
- bool linked = local_group.visit([&](soinfo* si) {
- if (!si->is_linked()) {
- if (!si->link_image(global_group, local_group, extinfo) ||
- !get_cfi_shadow()->AfterLoad(si, solist_get_head())) {
- return false;
+ soinfo_list_t global_group = local_group_ns->get_global_group();
+ bool linked = local_group.visit([&](soinfo* si) {
+ // Even though local group may contain accessible soinfos from other namesapces
+ // we should avoid linking them (because if they are not linked -> they
+ // are in the local_group_roots and will be linked later).
+ if (!si->is_linked() && si->get_primary_namespace() == local_group_ns) {
+ if (!si->link_image(global_group, local_group, extinfo) ||
+ !get_cfi_shadow()->AfterLoad(si, solist_get_head())) {
+ return false;
+ }
}
- }
- return true;
- });
-
- if (linked) {
- local_group.for_each([](soinfo* si) {
- if (!si->is_linked()) {
- si->set_linked();
- }
+ return true;
});
- failure_guard.Disable();
+ if (!linked) {
+ return false;
+ }
}
- return linked;
+ // Step 7: Mark all load_tasks as linked and increment refcounts
+ // for references between load_groups (at this point it does not matter if
+ // referenced load_groups were loaded by previous dlopen or as part of this
+ // one on step 6)
+ if (start_with != nullptr && add_as_children) {
+ start_with->set_linked();
+ }
+
+ for (auto&& task : load_tasks) {
+ soinfo* si = task->get_soinfo();
+ si->set_linked();
+ }
+
+ for (auto&& task : load_tasks) {
+ soinfo* si = task->get_soinfo();
+ soinfo* needed_by = task->get_needed_by();
+ if (needed_by != nullptr &&
+ needed_by != start_with &&
+ needed_by->get_local_group_root() != si->get_local_group_root()) {
+ si->increment_ref_count();
+ }
+ }
+
+
+ return true;
}
static soinfo* find_library(android_namespace_t* ns,
const char* name, int rtld_flags,
const android_dlextinfo* extinfo,
soinfo* needed_by) {
- soinfo* si;
+ soinfo* si = nullptr;
- // readers_map is shared across recursive calls to find_libraries.
- // However, the map is not shared across different threads.
- std::unordered_map<const soinfo*, ElfReader> readers_map;
if (name == nullptr) {
si = solist_get_somain();
} else if (!find_libraries(ns,
@@ -1745,8 +1768,10 @@
rtld_flags,
extinfo,
false /* add_as_children */,
- true /* search_linked_namespaces */,
- readers_map)) {
+ true /* search_linked_namespaces */)) {
+ if (si != nullptr) {
+ soinfo_unload(si);
+ }
return nullptr;
}
@@ -1755,18 +1780,26 @@
return si;
}
-static void soinfo_unload(soinfo* si) {
- soinfo* root = si->is_linked() ? si->get_local_group_root() : si;
+static void soinfo_unload(soinfo* unload_si) {
+ // Note that the library can be loaded but not linked;
+ // in which case there is no root but we still need
+ // to walk the tree and unload soinfos involved.
+ //
+ // This happens on unsuccessful dlopen, when one of
+ // the DT_NEEDED libraries could not be linked/found.
+ bool is_linked = unload_si->is_linked();
+ soinfo* root = is_linked ? unload_si->get_local_group_root() : unload_si;
LD_LOG(kLogDlopen,
"... dlclose(realpath=\"%s\"@%p) ... load group root is \"%s\"@%p",
- si->get_realpath(),
- si,
+ unload_si->get_realpath(),
+ unload_si,
root->get_realpath(),
root);
ScopedTrace trace((std::string("unload ") + root->get_realpath()).c_str());
+ size_t ref_count = is_linked ? root->decrement_ref_count() : 0;
if (!root->can_unload()) {
LD_LOG(kLogDlopen,
"... dlclose(root=\"%s\"@%p) ... not unloading - the load group is flagged with NODELETE",
@@ -1775,48 +1808,17 @@
return;
}
- soinfo_unload(&root, 1);
-}
-
-static void soinfo_unload(soinfo* soinfos[], size_t count) {
- // Note that the library can be loaded but not linked;
- // in which case there is no root but we still need
- // to walk the tree and unload soinfos involved.
- //
- // This happens on unsuccessful dlopen, when one of
- // the DT_NEEDED libraries could not be linked/found.
- if (count == 0) {
+ if (ref_count > 0) {
+ LD_LOG(kLogDlopen,
+ "... dlclose(root=\"%s\"@%p) ... not unloading - decrementing ref_count to %zd",
+ root->get_realpath(),
+ root,
+ ref_count);
return;
}
soinfo_list_t unload_list;
- for (size_t i = 0; i < count; ++i) {
- soinfo* si = soinfos[i];
-
- if (si->can_unload()) {
- size_t ref_count = si->is_linked() ? si->decrement_ref_count() : 0;
- if (ref_count == 0) {
- unload_list.push_back(si);
- } else {
- LD_LOG(kLogDlopen,
- "... dlclose(root=\"%s\"@%p) ... not unloading - decrementing ref_count to %zd",
- si->get_realpath(),
- si,
- ref_count);
- }
- } else {
- LD_LOG(kLogDlopen,
- "... dlclose(root=\"%s\"@%p) ... not unloading - the load group is flagged with NODELETE",
- si->get_realpath(),
- si);
- return;
- }
- }
-
- // This is used to identify soinfos outside of the load-group
- // note that we cannot have > 1 in the array and have any of them
- // linked. This is why we can safely use the first one.
- soinfo* root = soinfos[0];
+ unload_list.push_back(root);
soinfo_list_t local_unload_list;
soinfo_list_t external_unload_list;
@@ -1900,12 +1902,17 @@
soinfo_free(si);
}
- while ((si = external_unload_list.pop_front()) != nullptr) {
- LD_LOG(kLogDlopen,
- "... dlclose: unloading external reference \"%s\"@%p ...",
- si->get_realpath(),
- si);
- soinfo_unload(si);
+ if (is_linked) {
+ while ((si = external_unload_list.pop_front()) != nullptr) {
+ LD_LOG(kLogDlopen,
+ "... dlclose: unloading external reference \"%s\"@%p ...",
+ si->get_realpath(),
+ si);
+ soinfo_unload(si);
+ }
+ } else {
+ LD_LOG(kLogDlopen,
+ "... dlclose: unload_si was not linked - not unloading external references ...");
}
}
@@ -3368,6 +3375,10 @@
bool soinfo::link_image(const soinfo_list_t& global_group, const soinfo_list_t& local_group,
const android_dlextinfo* extinfo) {
+ if (is_image_linked()) {
+ // already linked.
+ return true;
+ }
local_group_root_ = local_group.front();
if (local_group_root_ == nullptr) {
@@ -3510,6 +3521,7 @@
}
notify_gdb_of_load(this);
+ set_image_linked();
return true;
}
diff --git a/linker/linker_main.cpp b/linker/linker_main.cpp
index 317f0d2..dc1fa75 100644
--- a/linker/linker_main.cpp
+++ b/linker/linker_main.cpp
@@ -384,9 +384,6 @@
const char** needed_library_names = &needed_library_name_list[0];
size_t needed_libraries_count = needed_library_name_list.size();
- // readers_map is shared across recursive calls to find_libraries so that we
- // don't need to re-load elf headers.
- std::unordered_map<const soinfo*, ElfReader> readers_map;
if (needed_libraries_count > 0 &&
!find_libraries(&g_default_namespace,
si,
@@ -399,7 +396,6 @@
nullptr,
true /* add_as_children */,
true /* search_linked_namespaces */,
- readers_map,
&namespaces)) {
__linker_cannot_link(g_argv[0]);
} else if (needed_libraries_count == 0) {
diff --git a/linker/linker_main.h b/linker/linker_main.h
index 2cf30c2..5641696 100644
--- a/linker/linker_main.h
+++ b/linker/linker_main.h
@@ -65,7 +65,6 @@
const android_dlextinfo* extinfo,
bool add_as_children,
bool search_linked_namespaces,
- std::unordered_map<const soinfo*, ElfReader>& readers_map,
std::vector<android_namespace_t*>* namespaces = nullptr);
void solist_add_soinfo(soinfo* si);
diff --git a/linker/linker_soinfo.cpp b/linker/linker_soinfo.cpp
index fbff7cf..dd91752 100644
--- a/linker/linker_soinfo.cpp
+++ b/linker/linker_soinfo.cpp
@@ -657,6 +657,10 @@
return (flags_ & FLAG_LINKED) != 0;
}
+bool soinfo::is_image_linked() const {
+ return (flags_ & FLAG_IMAGE_LINKED) != 0;
+}
+
bool soinfo::is_main_executable() const {
return (flags_ & FLAG_EXE) != 0;
}
@@ -669,6 +673,10 @@
flags_ |= FLAG_LINKED;
}
+void soinfo::set_image_linked() {
+ flags_ |= FLAG_IMAGE_LINKED;
+}
+
void soinfo::set_linker_flag() {
flags_ |= FLAG_LINKER;
}
@@ -677,8 +685,8 @@
flags_ |= FLAG_EXE;
}
-void soinfo::increment_ref_count() {
- local_group_root_->ref_count_++;
+size_t soinfo::increment_ref_count() {
+ return ++local_group_root_->ref_count_;
}
size_t soinfo::decrement_ref_count() {
diff --git a/linker/linker_soinfo.h b/linker/linker_soinfo.h
index 6f472b5..273c36c 100644
--- a/linker/linker_soinfo.h
+++ b/linker/linker_soinfo.h
@@ -41,6 +41,17 @@
#define FLAG_GNU_HASH 0x00000040 // uses gnu hash
#define FLAG_MAPPED_BY_CALLER 0x00000080 // the map is reserved by the caller
// and should not be unmapped
+#define FLAG_IMAGE_LINKED 0x00000100 // Is image linked - this is a guard on link_image.
+ // The difference between this flag and
+ // FLAG_LINKED is that FLAG_LINKED
+ // means is set when load_group is
+ // successfully loaded whereas this
+ // flag is set to avoid linking image
+ // when link_image called for the
+ // second time. This situation happens
+ // when load group is crossing
+ // namespace boundary twice and second
+ // local group depends on the same libraries.
#define FLAG_NEW_SOINFO 0x40000000 // new soinfo format
#define SOINFO_VERSION 3
@@ -243,7 +254,7 @@
void set_main_executable();
void set_nodelete();
- void increment_ref_count();
+ size_t increment_ref_count();
size_t decrement_ref_count();
soinfo* get_local_group_root() const;
@@ -273,6 +284,9 @@
void* to_handle();
private:
+ bool is_image_linked() const;
+ void set_image_linked();
+
bool elf_lookup(SymbolName& symbol_name, const version_info* vi, uint32_t* symbol_index) const;
ElfW(Sym)* elf_addr_lookup(const void* addr);
bool gnu_lookup(SymbolName& symbol_name, const version_info* vi, uint32_t* symbol_index) const;
diff --git a/tests/dlext_test.cpp b/tests/dlext_test.cpp
index 249d341..04b83f2 100644
--- a/tests/dlext_test.cpp
+++ b/tests/dlext_test.cpp
@@ -1051,6 +1051,87 @@
"\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
}
+TEST(dlext, ns_unload_between_namespaces_missing_symbol_direct) {
+ ASSERT_TRUE(android_init_anonymous_namespace(g_core_shared_libs.c_str(), nullptr));
+
+ const std::string public_ns_search_path = get_testlib_root() + "/public_namespace_libs";
+ const std::string private_ns_search_path = get_testlib_root() + "/private_namespace_libs";
+
+ android_namespace_t* ns_public =
+ android_create_namespace("public",
+ nullptr,
+ public_ns_search_path.c_str(),
+ ANDROID_NAMESPACE_TYPE_ISOLATED,
+ nullptr,
+ nullptr);
+
+ ASSERT_TRUE(android_link_namespaces(ns_public, nullptr, g_core_shared_libs.c_str())) << dlerror();
+
+ android_namespace_t* ns_private =
+ android_create_namespace("private",
+ nullptr,
+ private_ns_search_path.c_str(),
+ ANDROID_NAMESPACE_TYPE_ISOLATED,
+ nullptr,
+ nullptr);
+
+ ASSERT_TRUE(android_link_namespaces(ns_private, ns_public, "libtest_missing_symbol.so")) << dlerror();
+ ASSERT_TRUE(android_link_namespaces(ns_private, nullptr, g_core_shared_libs.c_str())) << dlerror();
+
+ android_dlextinfo extinfo;
+ extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
+ extinfo.library_namespace = ns_private;
+
+ void* handle = android_dlopen_ext((public_ns_search_path + "/libtest_missing_symbol.so").c_str(),
+ RTLD_NOW,
+ &extinfo);
+ ASSERT_TRUE(handle == nullptr);
+ ASSERT_EQ(std::string("dlopen failed: cannot locate symbol \"dlopen_testlib_missing_symbol\" referenced by \"") +
+ public_ns_search_path + "/libtest_missing_symbol.so\"...",
+ dlerror());
+}
+
+TEST(dlext, ns_unload_between_namespaces_missing_symbol_indirect) {
+ ASSERT_TRUE(android_init_anonymous_namespace(g_core_shared_libs.c_str(), nullptr));
+
+ const std::string public_ns_search_path = get_testlib_root() + "/public_namespace_libs";
+ const std::string private_ns_search_path = get_testlib_root() + "/private_namespace_libs";
+
+ android_namespace_t* ns_public =
+ android_create_namespace("public",
+ nullptr,
+ public_ns_search_path.c_str(),
+ ANDROID_NAMESPACE_TYPE_ISOLATED,
+ nullptr,
+ nullptr);
+
+ ASSERT_TRUE(android_link_namespaces(ns_public, nullptr, g_core_shared_libs.c_str())) << dlerror();
+
+ android_namespace_t* ns_private =
+ android_create_namespace("private",
+ nullptr,
+ private_ns_search_path.c_str(),
+ ANDROID_NAMESPACE_TYPE_ISOLATED,
+ nullptr,
+ nullptr);
+
+ ASSERT_TRUE(android_link_namespaces(ns_private,
+ ns_public,
+ "libnstest_public.so:libtest_missing_symbol_child_public.so")
+ ) << dlerror();
+ ASSERT_TRUE(android_link_namespaces(ns_private, nullptr, g_core_shared_libs.c_str())) << dlerror();
+
+ android_dlextinfo extinfo;
+ extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
+ extinfo.library_namespace = ns_private;
+
+ void* handle = android_dlopen_ext("libtest_missing_symbol_root.so", RTLD_NOW, &extinfo);
+ ASSERT_TRUE(handle == nullptr);
+ ASSERT_EQ(std::string("dlopen failed: cannot locate symbol \"dlopen_testlib_missing_symbol\" referenced by \"") +
+ private_ns_search_path + "/libtest_missing_symbol_root.so\"...",
+ dlerror());
+}
+
TEST(dlext, ns_greylist_enabled) {
ASSERT_TRUE(android_init_anonymous_namespace(g_core_shared_libs.c_str(), nullptr));
diff --git a/tests/libs/Android.bp b/tests/libs/Android.bp
index 8d0271a..e45eb6e 100644
--- a/tests/libs/Android.bp
+++ b/tests/libs/Android.bp
@@ -113,6 +113,62 @@
}
// -----------------------------------------------------------------------------
+// Library used by dlext direct unload on the namespace boundary tests
+// -----------------------------------------------------------------------------
+cc_test_library {
+ name: "libtest_missing_symbol",
+ defaults: ["bionic_testlib_defaults"],
+ srcs: ["dlopen_testlib_missing_symbol.cpp"],
+ allow_undefined_symbols: true,
+ relative_install_path: "bionic-loader-test-libs/public_namespace_libs",
+}
+
+
+// -----------------------------------------------------------------------------
+// Library used by dlext indirect unload on the namespace boundary tests
+//
+// These libraries produce following dependency graph:
+// libtest_missing_symbol_root (private ns)
+// +-> libbnstest_public (public ns)
+// +-> libtest_missing_symbol_child_public (public ns)
+// +-> libnstest_public (public ns)
+// +-> libtest_missing_symbol_child_private (private_ns)
+// +-> libnstest_public (public_ns)
+//
+// All libraries except libtest_missing_symbol are located in
+// private_namespace_libs/
+// -----------------------------------------------------------------------------
+cc_test_library {
+ name: "libtest_missing_symbol_child_public",
+ defaults: ["bionic_testlib_defaults"],
+ srcs: ["empty.cpp"],
+ relative_install_path: "bionic-loader-test-libs/public_namespace_libs",
+ shared_libs: ["libnstest_public"],
+}
+
+cc_test_library {
+ name: "libtest_missing_symbol_child_private",
+ defaults: ["bionic_testlib_defaults"],
+ srcs: ["empty.cpp"],
+ relative_install_path: "bionic-loader-test-libs/private_namespace_libs",
+ shared_libs: ["libnstest_public"],
+}
+
+cc_test_library {
+ name: "libtest_missing_symbol_root",
+ defaults: ["bionic_testlib_defaults"],
+ srcs: ["dlopen_testlib_missing_symbol.cpp"],
+ relative_install_path: "bionic-loader-test-libs/private_namespace_libs",
+ allow_undefined_symbols: true,
+ shared_libs: [
+ "libnstest_public",
+ "libtest_missing_symbol_child_public",
+ "libtest_missing_symbol_child_private",
+ ],
+}
+
+// -----------------------------------------------------------------------------
+// -----------------------------------------------------------------------------
// Library used by dlfcn nodelete tests
// -----------------------------------------------------------------------------
cc_test_library {
@@ -142,8 +198,65 @@
// -----------------------------------------------------------------------------
// Build test helper libraries for linker namespaces
+//
+// This set of libraries is used to verify linker namespaces.
+//
+// Test cases
+// 1. Check that private libraries loaded in different namespaces are
+// different. Check that dlsym does not confuse them.
+// 2. Check that public libraries loaded in different namespaces are shared
+// between them.
+// 3. Check that namespace sticks on dlopen
+// 4. Check that having access to shared library (libnstest_public.so)
+// does not expose symbols from dependent library (libnstest_public_internal.so)
+//
+// Dependency tree (visibility)
+// libnstest_root.so (this should be local to the namespace)
+// +-> libnstest_public.so
+// +-> libnstest_public_internal.so
+// +-> libnstest_private.so
+//
+// libnstest_dlopened.so (library in private namespace dlopened from libnstest_root.so)
// -----------------------------------------------------------------------------
-// include $(LOCAL_PATH)/Android.build.linker_namespaces.mk
+cc_test_library {
+ name: "libnstest_root",
+ defaults: ["bionic_testlib_defaults"],
+ srcs: ["namespaces_root.cpp"],
+ relative_install_path: "bionic-loader-test-libs/private_namespace_libs",
+ shared_libs: [
+ "libnstest_public",
+ "libnstest_private",
+ ],
+}
+
+cc_test_library {
+ name: "libnstest_public_internal",
+ defaults: ["bionic_testlib_defaults"],
+ srcs: ["namespaces_public_internal.cpp"],
+ relative_install_path: "bionic-loader-test-libs/public_namespace_libs",
+}
+
+cc_test_library {
+ name: "libnstest_public",
+ defaults: ["bionic_testlib_defaults"],
+ srcs: ["namespaces_public.cpp"],
+ relative_install_path: "bionic-loader-test-libs/public_namespace_libs",
+ shared_libs: ["libnstest_public_internal"],
+}
+
+cc_test_library {
+ name: "libnstest_private",
+ defaults: ["bionic_testlib_defaults"],
+ srcs: ["namespaces_private.cpp"],
+ relative_install_path: "bionic-loader-test-libs/private_namespace_libs",
+}
+
+cc_test_library {
+ name: "libnstest_dlopened",
+ defaults: ["bionic_testlib_defaults"],
+ srcs: ["namespaces_dlopened.cpp"],
+ relative_install_path: "bionic-loader-test-libs/private_namespace_libs",
+}
// -----------------------------------------------------------------------------
// Build DT_RUNPATH test helper libraries
diff --git a/tests/libs/Android.build.linker_namespaces.mk b/tests/libs/Android.build.linker_namespaces.mk
index cd9d7f1..e2b01a7 100644
--- a/tests/libs/Android.build.linker_namespaces.mk
+++ b/tests/libs/Android.build.linker_namespaces.mk
@@ -19,51 +19,6 @@
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
-# Test cases
-# 1. Check that private libraries loaded in different namespaces are
-# different. Check that dlsym does not confuse them.
-# 2. Check that public libraries loaded in different namespaces are shared
-# between them.
-# 3. Check that namespace sticks on dlopen
-# 4. Check that having access to shared library (libnstest_public.so)
-# does not expose symbols from dependent library (libnstest_public_internal.so)
-#
-# Dependency tree (visibility)
-# libnstest_root.so (this should be local to the namespace)
-# +-> libnstest_public.so
-# +-> libnstest_public_internal.so
-# +-> libnstest_private.so
-#
-# libnstest_dlopened.so (library in private namespace dlopened from libnstest_root.so)
-# -----------------------------------------------------------------------------
-libnstest_root_src_files := namespaces_root.cpp
-libnstest_root_shared_libraries := libnstest_public libnstest_private
-libnstest_root_relative_install_path := private_namespace_libs
-module := libnstest_root
-include $(LOCAL_PATH)/Android.build.testlib.target.mk
-
-libnstest_public_internal_src_files := namespaces_public_internal.cpp
-module := libnstest_public_internal
-libnstest_public_internal_relative_install_path := public_namespace_libs
-include $(LOCAL_PATH)/Android.build.testlib.target.mk
-
-libnstest_public_src_files := namespaces_public.cpp
-libnstest_public_shared_libraries := libnstest_public_internal
-module := libnstest_public
-libnstest_public_relative_install_path := public_namespace_libs
-include $(LOCAL_PATH)/Android.build.testlib.target.mk
-
-libnstest_private_src_files := namespaces_private.cpp
-libnstest_private_relative_install_path := private_namespace_libs
-module := libnstest_private
-include $(LOCAL_PATH)/Android.build.testlib.target.mk
-
-libnstest_dlopened_src_files := namespaces_dlopened.cpp
-libnstest_dlopened_relative_install_path := private_namespace_libs
-module := libnstest_dlopened
-include $(LOCAL_PATH)/Android.build.testlib.target.mk
-
-# -----------------------------------------------------------------------------
# This set of libraries is to test isolated namespaces
#
# Isolated namespaces do not allow loading of the library outside of
diff --git a/tests/libs/dlopen_testlib_missing_symbol.cpp b/tests/libs/dlopen_testlib_missing_symbol.cpp
new file mode 100644
index 0000000..0f73c60
--- /dev/null
+++ b/tests/libs/dlopen_testlib_missing_symbol.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+
+extern "C" void dlopen_testlib_missing_symbol();
+
+extern "C" bool dlopen_testlib_simple_func() {
+ dlopen_testlib_missing_symbol();
+ return true;
+}