Android Linker(一) 从loadLibrary开始-----上层调用流程

阅读源码版本: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类开始对文件解析,准备加载文件。至此,通过上层调用的过程基本就告一段落了。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值