static std::vector<std::string> g_ld_preload_names;
static bool g_public_namespace_initialized;
-static soinfo_list_t g_public_namespace;
+
+// TODO (dimitry): Remove once interface between libnativeloader and the linker is updated
+static std::unordered_set<std::string> g_public_namespace_sonames;
#if STATS
struct linker_stats_t {
static deleter_t deleter;
- static LoadTask* create(const char* name, soinfo* needed_by,
+ static LoadTask* create(const char* name,
+ soinfo* needed_by,
std::unordered_map<const soinfo*, ElfReader>* readers_map) {
LoadTask* ptr = TypeBasedAllocator<LoadTask>::alloc();
return new (ptr) LoadTask(name, needed_by, readers_map);
}
private:
- LoadTask(const char* name, soinfo* needed_by,
+ LoadTask(const char* name,
+ soinfo* needed_by,
std::unordered_map<const soinfo*, ElfReader>* readers_map)
: name_(name), needed_by_(needed_by), si_(nullptr),
fd_(-1), close_fd_(false), file_offset_(0), elf_readers_map_(readers_map),
soinfo* si = ns->soinfo_list().find_if(predicate);
- // check public namespace
- if (si == nullptr) {
- si = g_public_namespace.find_if(predicate);
- if (si != nullptr) {
- ns->add_soinfo(si);
- }
- }
-
if (si != nullptr) {
TRACE("library \"%s\" is already loaded under different name/path \"%s\" - "
"will return existing soinfo", name, si->get_realpath());
if (!ns->is_accessible(realpath)) {
// TODO(dimitry): workaround for http://b/26394120 - the grey-list
+
+ // TODO(dimitry) before O release: add a namespace attribute to have this enabled
+ // only for classloader-namespaces
const soinfo* needed_by = task->is_dt_needed() ? task->get_needed_by() : nullptr;
if (is_greylisted(name, needed_by)) {
// print warning only if needed by non-system library
});
}
+static std::string resolve_soname(const std::string& name) {
+ // We assume that soname equals to basename here
+
+ // TODO(dimitry): consider having honest absolute-path -> soname resolution
+ // note that since we might end up refusing to load this library because
+ // it is not in shared libs list we need to get the soname without actually loading
+ // the library.
+ //
+ // On the other hand there are several places where we already assume that
+ // soname == basename in particular for any not-loaded library mentioned
+ // in DT_NEEDED list.
+ return basename(name.c_str());
+}
+
+
+static bool find_library_in_linked_namespace(const android_namespace_link_t& namespace_link,
+ LoadTask* task,
+ int rtld_flags) {
+ android_namespace_t* ns = namespace_link.linked_namespace();
+
+ soinfo* candidate;
+ bool loaded = false;
+
+ std::string soname;
+ if (find_loaded_library_by_soname(ns, task->get_name(), &candidate)) {
+ loaded = true;
+ soname = candidate->get_soname();
+ } else {
+ soname = resolve_soname(task->get_name());
+ }
+
+ if (!namespace_link.is_accessible(soname.c_str())) {
+ // the library is not accessible via namespace_link
+ return false;
+ }
+
+ // if library is already loaded - return it
+ if (loaded) {
+ task->set_soinfo(candidate);
+ return true;
+ }
+
+ // try to load the library - once namespace boundary is crossed
+ // we need to load a library within separate load_group
+ // to avoid using symbols from foreign namespace while.
+ //
+ // All symbols during relocation should be resolved within a
+ // namespace to preserve library locality to a namespace.
+ const char* name = task->get_name();
+ if (find_libraries(ns,
+ task->get_needed_by(),
+ &name,
+ 1,
+ &candidate,
+ nullptr /* ld_preloads */,
+ 0 /* ld_preload_count*/,
+ rtld_flags,
+ nullptr /* extinfo*/,
+ false /* add_as_children */,
+ false /* search_linked_namespaces */)) {
+ task->set_soinfo(candidate);
+ return true;
+ }
+
+ return false;
+}
+
static bool find_library_internal(android_namespace_t* ns,
LoadTask* task,
ZipArchiveCache* zip_archive_cache,
LoadTaskList* load_tasks,
- int rtld_flags) {
+ int rtld_flags,
+ bool search_linked_namespaces) {
soinfo* candidate;
if (find_loaded_library_by_soname(ns, task->get_name(), &candidate)) {
return true;
}
- if (ns != &g_default_namespace) {
- // check public namespace
- candidate = g_public_namespace.find_if([&](soinfo* si) {
- return strcmp(task->get_name(), si->get_soname()) == 0;
- });
-
- if (candidate != nullptr) {
- ns->add_soinfo(candidate);
- task->set_soinfo(candidate);
- return true;
- }
- }
-
// Library might still be loaded, the accurate detection
// of this fact is done by load_library.
TRACE("[ \"%s\" find_loaded_library_by_soname failed (*candidate=%s@%p). Trying harder...]",
task->get_name(), candidate == nullptr ? "n/a" : candidate->get_realpath(), candidate);
- return load_library(ns, task, zip_archive_cache, load_tasks, rtld_flags);
+ if (load_library(ns, task, zip_archive_cache, load_tasks, rtld_flags)) {
+ return true;
+ }
+
+ if (search_linked_namespaces) {
+ // if a library was not found - look into linked namespaces
+ for (auto& linked_namespace : ns->linked_namespaces()) {
+ if (find_library_in_linked_namespace(linked_namespace,
+ task,
+ rtld_flags)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
}
static void soinfo_unload(soinfo* si);
size_t ld_preloads_count,
int rtld_flags,
const android_dlextinfo* extinfo,
- bool add_as_children) {
+ bool add_as_children,
+ bool search_linked_namespaces) {
// Step 0: prepare.
LoadTaskList load_tasks;
std::unordered_map<const soinfo*, ElfReader> readers_map;
task->set_extinfo(is_dt_needed ? nullptr : extinfo);
task->set_dt_needed(is_dt_needed);
- if(!find_library_internal(ns, task, &zip_archive_cache, &load_tasks, rtld_flags)) {
+ if (!find_library_internal(ns,
+ task,
+ &zip_archive_cache,
+ &load_tasks,
+ rtld_flags,
+ search_linked_namespaces || is_dt_needed)) {
return false;
}
if (is_dt_needed) {
needed_by->add_child(si);
- }
- if (si->is_linked()) {
- si->increment_ref_count();
+ if (si->is_linked()) {
+ si->increment_ref_count();
+ }
}
// When ld_preloads is not null, the first
return true;
});
- // We need to increment ref_count in case
- // the root of the local group was not linked.
- bool was_local_group_root_linked = local_group.front()->is_linked();
-
bool linked = local_group.visit([&](soinfo* si) {
if (!si->is_linked()) {
if (!si->link_image(global_group, local_group, extinfo) ||
failure_guard.disable();
}
- if (!was_local_group_root_linked) {
- local_group.front()->increment_ref_count();
- }
-
return linked;
}
if (name == nullptr) {
si = solist_get_somain();
- } else if (!find_libraries(ns, needed_by, &name, 1, &si, nullptr, 0, rtld_flags,
- extinfo, /* add_as_children */ false)) {
+ } else if (!find_libraries(ns,
+ needed_by,
+ &name,
+ 1,
+ &si,
+ nullptr,
+ 0,
+ rtld_flags,
+ extinfo,
+ false /* add_as_children */,
+ true /* search_linked_namespaces */)) {
return nullptr;
}
+ si->increment_ref_count();
+
return si;
}
return false;
}
- std::vector<std::string> sonames = android::base::Split(public_ns_sonames, ":");
+ auto sonames = android::base::Split(public_ns_sonames, ":");
ProtectedDataGuard guard;
- auto failure_guard = make_scope_guard([&]() {
- g_public_namespace.clear();
- });
-
- for (const auto& soname : sonames) {
- soinfo* candidate = nullptr;
-
- find_loaded_library_by_soname(&g_default_namespace, soname.c_str(), &candidate);
-
- if (candidate == nullptr) {
- DL_ERR("error initializing public namespace: a library with soname \"%s\""
- " was not found in the default namespace", soname.c_str());
- return false;
- }
-
- candidate->set_nodelete();
- g_public_namespace.push_back(candidate);
- }
+ g_public_namespace_sonames = std::unordered_set<std::string>(sonames.begin(), sonames.end());
g_public_namespace_initialized = true;
g_public_namespace_initialized = false;
return false;
}
+
g_anonymous_namespace = anon_ns;
- failure_guard.disable();
return true;
}
add_soinfos_to_namespace(get_shared_group(parent_namespace), ns);
}
+ // link it to default namespace
+ // TODO (dimitry): replace this with user-supplied link once interface is updated
+ ns->add_linked_namespace(&g_default_namespace, g_public_namespace_sonames);
+
return ns;
}
#include <string>
#include <vector>
+#include <unordered_set>
+
+struct android_namespace_t;
+
+struct android_namespace_link_t {
+ public:
+ android_namespace_link_t(android_namespace_t* linked_namespace,
+ const std::unordered_set<std::string>& shared_lib_sonames)
+ : linked_namespace_(linked_namespace), shared_lib_sonames_(shared_lib_sonames)
+ {}
+
+ android_namespace_t* linked_namespace() const {
+ return linked_namespace_;
+ }
+
+ bool is_accessible(const char* soname) const {
+ return shared_lib_sonames_.find(soname) != shared_lib_sonames_.end();
+ }
+
+ private:
+ android_namespace_t* const linked_namespace_;
+ const std::unordered_set<std::string> shared_lib_sonames_;
+};
struct android_namespace_t {
public:
permitted_paths_ = permitted_paths;
}
+ const std::vector<android_namespace_link_t>& linked_namespaces() const {
+ return linked_namespaces_;
+ }
+ void add_linked_namespace(android_namespace_t* linked_namespace,
+ const std::unordered_set<std::string>& shared_lib_sonames) {
+ linked_namespaces_.push_back(android_namespace_link_t(linked_namespace, shared_lib_sonames));
+ }
+
void add_soinfo(soinfo* si) {
soinfo_list_.push_back(si);
}
std::vector<std::string> ld_library_paths_;
std::vector<std::string> default_library_paths_;
std::vector<std::string> permitted_paths_;
+ // Loader looks into linked namespace if it was not able
+ // to find a library in this namespace. Note that library
+ // lookup in linked namespaces are limited by the list of
+ // shared sonames.
+ std::vector<android_namespace_link_t> linked_namespaces_;
soinfo_list_t soinfo_list_;
DISALLOW_COPY_AND_ASSIGN(android_namespace_t);