阅读源码版本:6.0.1
阅读工具:Android Studio 2.2.2 Notepad++
参考链接:
http://www.tuicool.com/articles/AfMZRbZ
http://docs.oracle.com/cd/E19253-01/819-7050/6n918j8nq/index.html#chapter6-71736
网上已经有很多写的不错的分析过程了,在这里记录下自己的分析历程。
Android中加载链接动态库,我么知道实质是最后调用/system/bin/linker进行对应操作,查看一下具体流程。
起初在Java层调用System.loadLiberary().
libcore\luni\src\main\java\java\lang\System.java
public final class System {
public static void loadLibrary(String libName) {
Runtime.getRuntime().loadLibrary(libName, VMStack.getCallingClassLoader());
}
}
调用./Runtime.java中的Runtime类的实例化对象,对应调用方法
public void loadLibrary(String nickname) {
loadLibrary(nickname, VMStack.getCallingClassLoader());
}
void loadLibrary(String libraryName, ClassLoader loader) {
....
String error = doLoad(filename, loader);
....
}
private String doLoad(String name, ClassLoader loader) {
synchronized (this) {
return nativeLoad(name, loader, ldLibraryPath);
}
}
private static native String nativeLoad(String filename, ClassLoader loader,
String ldLibraryPath);
Java层调用来调用去,还是进到Native中了.
art\runtime\native\java_lang_Runtime.cc
static jstring Runtime_nativeLoad(JNIEnv* env, jclass, jstring javaFilename, jobject javaLoader, jstring javaLdLibraryPathJstr) {
bool success = vm->LoadNativeLibrary(env, filename.c_str(), javaLoader, &error_msg);
}
在./java_vm_ext.cc中,实现LoadNativeLibrary.
bool JavaVMExt::LoadNativeLibrary(JNIEnv* env, const std::string& path, jobject class_loader, std::string* error_msg) {
void* handle = dlopen(path_str, RTLD_NOW);
}
走到最后,不出意外的还是调用了dlopen,并且在获取到handle之后还调用了JNI_OnLoad函数.
继续.
bionic\linker\dlfcn.cpp
void* dlopen(const char* filename, int flags) {
return dlopen_ext(filename, flags, nullptr);
}
static void* dlopen_ext(const char* filename, int flags, const android_dlextinfo* extinfo) {
....
soinfo* result = do_dlopen(filename, flags, extinfo);
....
}
soinfo是一个非常重要的结构体,包含了动态库的所有信息。结构体定义在./linker.h.转到./linker.cpp中继续.
soinfo* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo) {
....
soinfo* si = find_library(name, flags, extinfo);
....
}
static soinfo* find_library(const char* name, int rtld_flags, const android_dlextinfo* extinfo) {
soinfo* si;
if (name == nullptr) {
si = somain;
} else if (!find_libraries(nullptr, &name, 1, &si, nullptr, 0, rtld_flags, extinfo)) {
return nullptr;
}
return si;
}
static bool find_libraries(soinfo* start_with, const char* const library_names[],
size_t library_names_count, soinfo* soinfos[], std::vector<soinfo*>* ld_preloads,
size_t ld_preloads_count, int rtld_flags, const android_dlextinfo* extinfo) {
....
soinfo* si = find_library_internal(load_tasks, task->get_name(), rtld_flags, extinfo);
....
}
static soinfo* find_library_internal(LoadTaskList& load_tasks, const char* name,int rtld_flags, const android_dlextinfo* extinfo) {
....
if (find_loaded_library_by_soname(name, &candidate)) {
return candidate;
}
....
soinfo* si = load_library(load_tasks, name, rtld_flags, extinfo);
....
}
static bool find_loaded_library_by_soname(const char* name, soinfo** candidate) {
....
for (soinfo* si = solist; si != nullptr; si = si->next) {
const char* soname = si->get_soname();
if (soname != nullptr && (strcmp(name, soname) == 0)) {
....
}
}
....
}
该文件开始进入了主要的加载流程,现在是开始的部分,大概是在已经加载的列表中根据名字路径查找是否加载了同样的动态库,如果找到了就返回,否则就开始调用load_library函数开始加载新的动态库.
static soinfo* load_library(LoadTaskList& load_tasks,const char* name, int rtld_flags,const android_dlextinfo* extinfo) {
....
int fd = open_library(name, &file_offset);
if (fd == -1) {
DL_ERR("library \"%s\" not found", name);
return nullptr;
}
soinfo* result = load_library(fd, file_offset, load_tasks, name, rtld_flags, extinfo);
....
}
static soinfo* load_library(int fd, off64_t file_offset,LoadTaskList& load_tasks,const char* name, int rtld_flags,const android_dlextinfo* extinfo) {
for (soinfo* si = solist; si != nullptr; si = si->next) {
if (si->get_st_dev() != 0 &&
si->get_st_ino() != 0 &&
si->get_st_dev() == file_stat.st_dev &&
si->get_st_ino() == file_stat.st_ino &&
si->get_file_offset() == file_offset) {
TRACE("library \"%s\" is already loaded under different name/path \"%s\" - "
"will return existing soinfo", name, si->get_realpath());
return si;
}
}
....
ElfReader elf_reader(realpath.c_str(), fd, file_offset, file_stat.st_size);
if (!elf_reader.Load(extinfo)) {
return nullptr;
}
soinfo* si = soinfo_alloc(realpath.c_str(), &file_stat, file_offset, rtld_flags);
if (si == nullptr) {
return nullptr;
}
si->base = elf_reader.load_start();
si->size = elf_reader.load_size();
si->load_bias = elf_reader.load_bias();
si->phnum = elf_reader.phdr_count();
si->phdr = elf_reader.loaded_phdr();
if (!si->prelink_image()) {
soinfo_free(si);
return nullptr;
}
for_each_dt_needed(si, [&] (const char* name) {
load_tasks.push_back(LoadTask::create(name, si));
});
return si;
}
调用open_library读取文件,发现还是没有死心,根据动态库相关属性进行判断,判断是否在其他路径下的相同so被加载了。等确定后开始新建soinfo结构对象,调用ELFReader类开始对文件解析,准备加载文件。至此,通过上层调用的过程基本就告一段落了。