private String doLoad(String name, ClassLoader loader){ String librarySearchPath = null; if (loader != null && loader instanceof BaseDexClassLoader) { BaseDexClassLoader dexClassLoader = (BaseDexClassLoader) loader; librarySearchPath = dexClassLoader.getLdLibraryPath(); } // nativeLoad should be synchronized so there's only one LD_LIBRARY_PATH in use regardless // of how many ClassLoaders are in the system, but dalvik doesn't support synchronized // internal natives. synchronized (this) { return nativeLoad(name, loader, librarySearchPath); } }
// TODO: should be synchronized, but dalvik doesn't support synchronized internal natives. privatestaticnative String nativeLoad(String filename, ClassLoader loader, String librarySearchPath);
std::string error_msg; { art::JavaVMExt* vm = art::Runtime::Current()->GetJavaVM(); bool success = vm->LoadNativeLibrary(env, filename.c_str(), javaLoader, javaLibrarySearchPath, &error_msg); if (success) { returnnullptr; } } // Don't let a pending exception from JNI_OnLoad cause a CheckJNI issue with NewStringUTF. env->ExceptionClear(); return env->NewStringUTF(error_msg.c_str()); }
// Open the shared library. Because we're using a full path, the system // doesn't have to search through LD_LIBRARY_PATH. (It may do so to // resolve this library's dependencies though.)
// Failures here are expected when java.library.path has several entries // and we have to hunt for the lib.
// Below we dlopen but there is no paired dlclose, this would be necessary if we supported // class unloading. Libraries will only be unloaded when the reference count (incremented by // dlopen) becomes zero from dlclose.
...... VLOG(jni) << "[Added shared library \"" << path << "\" for ClassLoader " << class_loader << "]"; ...... bool was_successful = false; void* sym; if (needs_native_bridge) { library->SetNeedsNativeBridge(); } sym = library->FindSymbol("JNI_OnLoad", nullptr); if (sym == nullptr) { VLOG(jni) << "[No JNI_OnLoad found in \"" << path << "\"]"; was_successful = true; } else { // Call JNI_OnLoad. We have to override the current class // loader, which will always be "null" since the stuff at the // top of the stack is around Runtime.loadLibrary(). (See // the comments in the JNI FindClass function.) ScopedLocalRef<jobject> old_class_loader(env, env->NewLocalRef(self->GetClassLoaderOverride())); self->SetClassLoaderOverride(class_loader);
VLOG(jni) << "[Calling JNI_OnLoad in \"" << path << "\"]"; typedefint(*JNI_OnLoadFn)(JavaVM*, void*); JNI_OnLoadFn jni_on_load = reinterpret_cast<JNI_OnLoadFn>(sym); int version = (*jni_on_load)(this, nullptr);
if (ns == nullptr) { // 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) { returnnullptr; } }
#if defined(__work_around_b_24465209__) uint32_t unused1; // DO NOT USE, maintained for compatibility. #endif
ElfW(Dyn)* dynamic;
#if defined(__work_around_b_24465209__) uint32_t unused2; // DO NOT USE, maintained for compatibility uint32_t unused3; // DO NOT USE, maintained for compatibility #endif
#if defined(__mips__) || !defined(__LP64__) // This is only used by mips and mips64, but needs to be here for // all 32-bit architectures to preserve binary compatibility. ElfW(Addr)** plt_got_; #endif
// When you read a virtual address from the ELF file, add this // value to get the corresponding address in the process' address space. ElfW(Addr) load_bias;
for (size_t i = 0; i < library_names_count; ++i) { constchar* name = library_names[i]; load_tasks.push_back(LoadTask::create(name, start_with, &readers_map)); }
// If soinfos array is null allocate one on stack. // The array is needed in case of failure; for example // when library_names[] = {libone.so, libtwo.so} and libone.so // is loaded correctly but libtwo.so failed for some reason. // In this case libone.so should be unloaded on return. // See also implementation of failure_guard below.
// list of libraries to link - see step 2. size_t soinfos_count = 0;
auto scope_guard = make_scope_guard([&]() { for (LoadTask* t : load_tasks) { LoadTask::deleter(t); } });
auto failure_guard = make_scope_guard([&]() { // Housekeeping soinfo_unload(soinfos, soinfos_count); });
ZipArchiveCache zip_archive_cache;
// Step 1: expand the list of load_tasks to include // all DT_NEEDED libraries (do not load them just yet) for (size_t i = 0; i<load_tasks.size(); ++i) { LoadTask* task = load_tasks[i]; soinfo* needed_by = task->get_needed_by();
if (si->is_linked()) { si->increment_ref_count(); }
// When ld_preloads is not null, the first // ld_preloads_count libs are in fact ld_preloads. if (ld_preloads != nullptr && soinfos_count < ld_preloads_count) { ld_preloads->push_back(si); }
if (soinfos_count < library_names_count) { soinfos[soinfos_count++] = si; } }
// Step 2: Load libraries in random order (see b/24047022) LoadTaskList load_list; for (auto&& task : load_tasks) { soinfo* si = task->get_soinfo(); auto pred = [&](const LoadTask* t) { return t->get_soinfo() == si; };
for (auto&& task : load_list) { if (!task->load()) { returnfalse; } }
// Step 3: pre-link all DT_NEEDED libraries in breadth first order. for (auto&& task : load_tasks) { soinfo* si = task->get_soinfo(); if (!si->is_linked() && !si->prelink_image()) { returnfalse; } }
// Step 4: Add LD_PRELOADed libraries to the global group for // future runs. There is no need to explicitly add them to // the global group for this run because they are going to // appear in the local group in the correct order. if (ld_preloads != nullptr) { for (auto&& si : *ld_preloads) { si->set_dt_flags_1(si->get_dt_flags_1() | DF_1_GLOBAL); } }
// 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)) { returnfalse; } }
returntrue; });
if (linked) { local_group.for_each([](soinfo* si) { if (!si->is_linked()) { si->set_linked(); } });
failure_guard.disable(); }
if (!was_local_group_root_linked) { local_group.front()->increment_ref_count(); }
voidsoinfo::call_constructors(){ if (constructors_called) { return; }
// We set constructors_called before actually calling the constructors, otherwise it doesn't // protect against recursive constructor calls. One simple example of constructor recursion // is the libc debug malloc, which is implemented in libc_malloc_debug_leak.so: // 1. The program depends on libc, so libc's constructor is called here. // 2. The libc constructor calls dlopen() to load libc_malloc_debug_leak.so. // 3. dlopen() calls the constructors on the newly created // soinfo for libc_malloc_debug_leak.so. // 4. The debug .so depends on libc, so CallConstructors is // called again with the libc soinfo. If it doesn't trigger the early- // out above, the libc constructor will be called again (recursively!). constructors_called = true;
if (!is_main_executable() && preinit_array_ != nullptr) { // The GNU dynamic linker silently ignores these, but we warn the developer. PRINT("\"%s\": ignoring DT_PREINIT_ARRAY in shared library!", get_realpath()); }
// DT_INIT should be called before DT_INIT_ARRAY if both are present. call_function("DT_INIT", init_func_); call_array("DT_INIT_ARRAY", init_array_, init_array_count_, false); }