没有合适的资源?快使用搜索试试~ 我知道了~
Android-so加载深入分析
需积分: 50 10 下载量 25 浏览量
2017-09-12
16:13:19
上传
评论 1
收藏 2.07MB PDF 举报
温馨提示
试读
38页
Android-so加载深入分析 Android-so加载深入分析 Android-so加载深入分析 Android-so加载深入分析 Android-so加载深入分析
资源推荐
资源详情
资源评论
目录
1 Java 层 ......................................................................................................................... 3
2 Native 层 ..................................................................................................................... 4
2.1 find_libraries()第一部分:初始化阶段 .......................................................... 9
2.2 find_libraries()第二部分:载入 so 到内存 .................................................... 9
2.2.1 load_library()第一部分:打开 so 文件 ............................................. 12
2.2.2 load_library()第二部分:映射 so 文件到内存 ................................. 12
2.2.3 load_library()第三部分:解析 dynamic section ............................... 21
2.3 find_libraries()第三部分:链接阶段 ............................................................ 28
3 附录 ......................................................................................................................... 37
本文对 Android 中 so 的加载进行了深入分析。通过分析相关源码,了解 linker
是如何将 so 文件加载到内存、如何进行链接操作。本文涉及的 Android 源码版
本是 Android L。阅读本文之前,希望读者了解一点 ELF 的文件格式,如果对 ELF
完全不 了解, 可 以 参 考 我 之 前 对 OAT 的分析
(https://github.com/ManyFace/ExtractDexFromOat)。由于水平有限,难免有所疏忽,
分析不够到位或者错误的地方,还请各位指正。
1 Java 层
Android 在 java 层加载 so 的接口是 System.loadLibrary(),本文以此为突破口,
逐步向下分析,得到 java 层函数的调用关系如图 1 所示。下面对每个函数进行
详细分析。
System.loadLibrary(libName)
Runtime.loadLibrary(...)
Runtime.doLoad(...)
Runtime.nativeLoad(...)
图 1 java 层函数调用关系图
System.loadLibrary()的源码如下:
987public static void loadLibrary(String libName) {
988 Runtime.getRuntime().loadLibrary(libName, VMStack.getCallingClassLoader());
989}
可以看到它是调用了 Runtime 类的 loadLibrary(),其源码如下:
从 上 可 知 , loadLibrary(String nickname) 调 用 了 它 的 一 个 重 载 函 数
loadLibrary(String libraryName, ClassLoader loader),其关键代码如下:
351 public void loadLibrary(String nickname) {
352 loadLibrary(nickname, VMStack.getCallingClassLoader());
353 }
358 void loadLibrary(String libraryName, ClassLoader loader) {
359 if (loader != null) {
360 String filename = loader.findLibrary(libraryName);//so 路径
361 … …
360 行获得 so 文件的绝对路径 filename,369 行调用 doLoad()来加载 so 文
件。doLoad(String name, ClassLoader loader)的源码如下:
428 行调用 nativeLoad()来加载 name 指向的.so 文件,nativeLoad()是 Runtime
类的一个 native 函数,在 native 层对应的函数为 Runtime_nativeLoad()。
2 Native 层
大家在看 native 层的分析时,可以结合附录中的图 11(字有点小)。从图 11
可知,本文主要是分析 dlopen()的实现。下面开始分析 native 层的代码。
Runtime_nativeLoad()的关键代码如下:
46static jstring Runtime_nativeLoad(JNIEnv* env, jclass, jstring javaFilename,
jobject javaLoader, jstring javaLdLibraryPath) {
47 ScopedUtfChars filename(env, javaFilename);
51 … …
67 std::string detail;
68 {
69 ScopedObjectAccess soa(env);
70 StackHandleScope<1> hs(soa.Self());
71 Handle<mirror::ClassLoader> classLoader(
72 hs.NewHandle(soa.Decode<mirror::ClassLoader*>(javaLoader)));
73 JavaVMExt* vm = Runtime::Current()->GetJavaVM();
74 bool success = vm->LoadNativeLibrary(filename.c_str(), classLoader,
&detail);//加载 so
75 if (success) {
76 return nullptr;
369 String error = doLoad(filename, loader);//加载
370 … …
373 return;
374 }
376 … …
396 }
400 private String doLoad(String name, ClassLoader loader) {
420 String ldLibraryPath = null;
421 if (loader != null && loader instanceof BaseDexClassLoader) {
422 ldLibraryPath = ((BaseDexClassLoader) loader).getLdLibraryPath();
423 }
427 synchronized (this) {
428 return nativeLoad(name, loader, ldLibraryPath);
429 }
430 }
77 }
78 }
74 行调用 JavaVMExt 类的 LoadNativeLibrary()函数来加载.so 文件,
filename 是.so 文件的路径,detail 用于存储加载过程中的 log 信息。
LoadNativeLibrary()的关键代码如下:
bool JavaVMExt::LoadNativeLibrary(const std::string& path,
3226 Handle<mirror::ClassLoader> class_loader,
3227 std::string* detail) {
3228 detail->clear();
3229//首先检查是否加载过该.so,加载过就不需要重复加载
3234 SharedLibrary* library;
3235 Thread* self = Thread::Current();
3236 {
3238 MutexLock mu(self, libraries_lock);
3239 library = libraries->Get(path);
3240 }
3241 if (library != nullptr) {
3242 if (library->GetClassLoader() != class_loader.Get()) {
3246 StringAppendF(detail, "Shared library \"%s\" already opened by "
3247 "ClassLoader %p; can't open in ClassLoader %p",
3248 path.c_str(), library->GetClassLoader(), class_loader.Get());
3249 LOG(WARNING) << detail;
3250 return false;
3251 }
3252 … …
3254 if (!library->CheckOnLoadResult()) {
3255 StringAppendF(detail, "JNI_OnLoad failed on a previous attempt "
3256 "to load \"%s\"", path.c_str());
3257 return false;
3258 }
3259 return true;
3260 }
3261//之前没有加载过
3275 self->TransitionFromRunnableToSuspended(kWaitingForJniOnLoad);
3276 const char* path_str = path.empty() ? nullptr : path.c_str();
3277 void* handle = dlopen(path_str, RTLD_LAZY); //用 dlopen 加载.so 文件
3279 … …
3285 self->TransitionFromSuspendedToRunnable();
3286 … …
3297 bool created_library = false;
3298 {
3299 MutexLock mu(self, libraries_lock);
剩余37页未读,继续阅读
资源评论
mylove2693
- 粉丝: 14
- 资源: 29
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功