// voidloadLibrary0(Class<?> fromClass, String libname) { ClassLoaderclassLoader= ClassLoader.getClassLoader(fromClass); loadLibrary0(classLoader, fromClass, libname); } privatesynchronizedvoidloadLibrary0(ClassLoader loader, Class<?> callerClass, String libname) { if (libname.indexOf((int)File.separatorChar) != -1) { thrownewUnsatisfiedLinkError( "Directory separator should not appear in library name: " + libname); } StringlibraryName= libname; // Android-note: BootClassLoader doesn't implement findLibrary(). http://b/111850480 // Android's class.getClassLoader() can return BootClassLoader where the RI would // have returned null; therefore we treat BootClassLoader the same as null here. if (loader != null && !(loader instanceof BootClassLoader)) { Stringfilename= loader.findLibrary(libraryName); if (filename == null) { // It's not necessarily true that the ClassLoader used // System.mapLibraryName, but the default setup does, and it's // misleading to say we didn't find "libMyLibrary.so" when we // actually searched for "liblibMyLibrary.so.so". thrownewUnsatisfiedLinkError(loader + " couldn't find \"" + System.mapLibraryName(libraryName) + "\""); } Stringerror= nativeLoad(filename, loader); if (error != null) { thrownewUnsatisfiedLinkError(error); } return; } // We know some apps use mLibPaths directly, potentially assuming it's not null. // Initialize it here to make sure apps see a non-null value. getLibPaths(); Stringfilename= System.mapLibraryName(libraryName); Stringerror= nativeLoad(filename, loader, callerClass); if (error != null) { thrownewUnsatisfiedLinkError(error); } }
不具体讨论函数中的详细逻辑流程,loadLibrary0 在 so 未加载情况下会调用 nativeLoad 方法。nativeLoad 函数如下:
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()); }
if (!is_linker()) { bionic_trace_begin((std::string("calling constructors: ") + get_realpath()).c_str()); }
// DT_INIT should be called before DT_INIT_ARRAY if both are present. // 在这里调用initarray和init call_function("DT_INIT", init_func_, get_realpath()); call_array("DT_INIT_ARRAY", init_array_, init_array_count_, false, get_realpath());
//查找JNI_OnLoad方法,所以我们在jni开发中动态注册就需要重写这个方法是有道理的 void* sym = library->FindSymbol("JNI_OnLoad", nullptr); // 其实sym有没有获取到值都不影响加载,JNI_OnLoad不是必须的 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 << "\"]"; using JNI_OnLoadFn = int(*)(JavaVM*, void*); JNI_OnLoadFn jni_on_load = reinterpret_cast<JNI_OnLoadFn>(sym); //主动去调用JNI_OnLoad方法,如果调用成功,返回版本号 int version = (*jni_on_load)(this, nullptr); //...省略 }
// No mutator lock since dlsym may block for a while if another thread is doing dlopen. void* FindSymbol(conststd::string& symbol_name, constchar* shorty = nullptr) REQUIRES(!Locks::mutator_lock_) { return NeedsNativeBridge() ? FindSymbolWithNativeBridge(symbol_name, shorty) : FindSymbolWithoutNativeBridge(symbol_name); }
// No mutator lock since dlsym may block for a while if another thread is doing dlopen. void* FindSymbolWithoutNativeBridge(conststd::string& symbol_name) REQUIRES(!Locks::mutator_lock_) { CHECK(!NeedsNativeBridge());
return dlsym(handle_, symbol_name.c_str()); }
JNI_OnLoad方法是在dlopen完全执行完毕之后调用的
要想hook JNI_OnLoad方法,直接在dlopenonleave的时候去hook
要想hook initarray和init方法,需要等到soinfo* si = find_library(ns, translated_name, flags, extinfo, caller);执行完毕,即so加载完毕之后再去hook,不然基址都获取不到