https://www.cnblogs.com/revercc/p/16299712.html
在linker初始化的时候linker_main函数在加载了所有ELF文件依赖的so库后,会先调用call_pre_init_constructors()和call_constructors()函数对so库执行一些初始化后在返回ELF文件的入口地址。
//加载所有的依赖库文件并进行重定位处理。
if (needed_libraries_count > 0 &&
!find_libraries(&g_default_namespace,
si,
needed_library_names,
needed_libraries_count,
nullptr,
&g_ld_preloads,
ld_preloads_count,
RTLD_GLOBAL,
nullptr,
true /* add_as_children */,
true /* search_linked_namespaces */,
&namespaces)) {
__linker_cannot_link(g_argv[0]);
} else if (needed_libraries_count == 0) {
if (!si->link_image(g_empty_list, soinfo_list_t::make_list(si), nullptr, nullptr)) {
__linker_cannot_link(g_argv[0]);
}
si->increment_ref_count();
}
//多所有加载的依赖库进行初始化。
si->call_pre_init_constructors();
si->call_constructors();
//返回ELF文件的入口地址
ElfW(Addr) entry = exe_info.entry_point;
TRACE("[ Ready to execute \"%s\" @ %p ]", si->get_realpath(), reinterpret_cast<void*>(entry));
return entry;
.preinit_array
call_pre_init_constructors函数会调用call_array加载DT_PREINIT_ARRAY数组中的所有函数并执行。
.init_array和.init
call_constructors函数调用call_function执行DT_INIT中的函数,调用call_array执行DT_INIT_ARRAY数组中的所有函数。
JNI_Onload
JAVA层加载一个so文件函数调用链如下
System.loadLibrary()
├─ loadLibrary0
│ └─ nativeload(Runtime_nativeLoad进入native层)
│ └─ JVM_NativeLoad
│ └─ JavaVMExt::LoadNativeLibrary
│ └─ OpenNativeLibrary
│ FindSymbol
└──────── jni_on_load
System.loadLibrary
JAVA层调用System.loadLibrary函数加载一个so文件,此函数会调用loadLibrary0
loadLibrary0
loadLibrary0会继续调用native函数nativeload去加载so文件。
Runtime_nativeLoad
nativeload对应的native层函数为Runtime_nativeLoad,此函数直接调用另一个函数JVM_NativeLoad
//libcore/ojluni/src/main/native/Runtime.c
JNIEXPORT jstring JNICALL
Runtime_nativeLoad(JNIEnv* env, jclass ignored, jstring javaFilename,
jobject javaLoader, jclass caller)
{
return JVM_NativeLoad(env, javaFilename, javaLoader, caller);
}
JVM_NativeLoad
JVM_NativeLoad在进行一些参数的检查后,通过JavaVM调用LoadNativeLibrary去加载so。
//art/openjdkjvm/OpenjdkJvm.cc
JNIEXPORT jstring JVM_NativeLoad(JNIEnv* env,
jstring javaFilename,
jobject javaLoader,
jclass caller) {
ScopedUtfChars filename(env, javaFilename);
if (filename.c_str() == nullptr) {
return nullptr;
}
std::string error_msg;
{
art::JavaVMExt* vm = art::Runtime::Current()->GetJavaVM();
bool success = vm->LoadNativeLibrary(env,
filename.c_str(),
javaLoader,
caller,
&error_msg);
if (success) {
return nullptr;
}
}
// Don't let a pending exception from JNI_OnLoad cause a CheckJNI issue with NewStringUTF.
env->ExceptionClear();
return env->NewStringUTF(error_msg.c_str());
}
JavaVMExt::LoadNativeLibrary
- 调用OpenNativeLibrary,其内部会调用dlopen加载so库(dlopen加载so库的时候会和linker初始化一样,先对此so库进行初始化,调用.preinit_array,.init_array,.init)
- 调用FindSymbol,其内部会调用dlsym获取JNI_OnLoad导出函数的地址
- 最后调用JNI_OnLoad函数进行动态注册
//art/runtime/jni/java_vm_ext.cc
bool JavaVMExt::LoadNativeLibrary(JNIEnv* env,
const std::string& path,
jobject class_loader,
jclass caller_class,
std::string* error_msg) {
//OpenNativeLibrary会调用dlopen加载so库
void* handle = android::OpenNativeLibrary(
env,
runtime_->GetTargetSdkVersion(),
path_str,
class_loader,
(caller_location.empty() ? nullptr : caller_location.c_str()),
library_path.get(),
&needs_native_bridge,
&nativeloader_error_msg);
VLOG(jni) << "[Call to dlopen(\"" << path << "\", RTLD_NOW) returned " << handle << "]";
//FindSymbol会调用dlsym获取JNI_OnLoad导出函数的地址
void* sym = library->FindSymbol("JNI_OnLoad", nullptr);
if (sym == nullptr) {
VLOG(jni) << "[No JNI_OnLoad found in \"" << path << "\"]";
was_successful = true;
} else {
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);
}
}
源码是基于android10.0.0_r7
标签:调用,nullptr,init,so,JNI,array,加载 From: https://www.cnblogs.com/revercc/p/16859449.html