searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

Android系统加载native库的流程和原理分析(上)

2023-06-08 11:36:54
85
0
本篇将介绍Android系统加载so库的流程,以及部分原理,希望看完可以解答如下疑问:
1、APP 优先使用哪个文件夹的so库;
2、APP 自带的so库是怎么使用的;
3、系统是通过什么加载so库的;
 
先看一个整体流程图:
通过流程可知,load一个native库主要分两步:
1、查找到so库在哪里;
2、将查找到的so库之后通过JVM调用C库函数进行真正的加载
 
先分析它是如何找到so库的:
runtime.java的findLibrary函数最后是用的DexPathList的findLibrary函数:
 
 
 
element.findNativeLibrary(fileName) 继续根据名字查找对应的文件在哪个目录中 ,这个方法优先会去找非zipDir目录的library,然后再去
找zipDir目录的library,而这个zipDir 实际上就是APP原本的目录
 
 
请注意,findNativeLibrary这个方法是NativeLibraryElement类的方法,这个类的对象是element,而这个element是从nativeLibraryPathElements中来的,
弄清楚nativeLibraryPathElements 这个是从哪来的,接下来具体找哪个目录就会比较清楚了。
 
 
 
从上面函数可知,系统会优先查找自己目录的libraries,然后再找APK 压缩文件中,最后才会查找Android 虚拟机环境变量目录中的libraries,
同时,nativeLibraryPathElements是通过 makePathElements(getAllNativeLibraryDirectories()) 制造出来的,我们接着往下看:
 
 
 
 
这个函数的是通过传进来的参数getAllNativeLibraryDirectories() 来进行生成对应的NativeLibraryElement数组的,这个数组其实就是根据传来的文件路径再次进行组装分割,
而核心的分割方法就是通过这个符号:
private static final String zipSeparator = "!/";
这也就是为何我们会发现如果有APP找不到库时,会有一个这样奇怪的路径,其实就是在这个函数里面处理的,
再次看到如下相关的异常LOG之后就会比较亲切了:
 
 
我们再看看getAllNativeLibraryDirectories() 是怎么获取路径的:
 
private List<File> getAllNativeLibraryDirectories() {
List<File> allNativeLibraryDirectories = new ArrayList<>(nativeLibraryDirectories);
allNativeLibraryDirectories.addAll(systemNativeLibraryDirectories);
return allNativeLibraryDirectories;
 
 
这个获取路径就简单了,就是从nativeLibraryDirectories 里面来的,所以最终核心的关键是nativeLibraryDirectories 是从哪来的,仔细看代码会发现前面DexPathList进行对象
构造的时候,已经将其进行了赋值:
this.nativeLibraryDirectories = splitPaths(librarySearchPath, false);
其就是将librarySearchPath 里面的文件路径进行了分割存储到了nativeLibraryDirectories中,而librarySearchPath是从DexPathList 这个构造函数里面传入的,
那么是谁对DexPathList进行构造的就很关键了。
我们通过流程图倒回去看看,是BaseDexClassLoader 创建的DexPathList对象:
public BaseDexClassLoader(String dexPath,
String librarySearchPath, ClassLoader parent, ClassLoader[] sharedLibraryLoaders,
boolean isTrusted) {
super(parent);
// Setup shared libraries before creating the path list. ART relies on the class loader
// hierarchy being finalized before loading dex files.
this.sharedLibraryLoaders = sharedLibraryLoaders == null
? null
: Arrays.copyOf(sharedLibraryLoaders, sharedLibraryLoaders.length);
this.pathList = new DexPathList(this, dexPath, librarySearchPath, null, isTrusted);
 
if (reporter != null) {
reportClassLoaderChain();
}
}
 
而BaseDexClassLoader的 librarySearchPath也是传进来的。
 
0条评论
0 / 1000
朱****春
17文章数
3粉丝数
朱****春
17 文章 | 3 粉丝
原创

Android系统加载native库的流程和原理分析(上)

2023-06-08 11:36:54
85
0
本篇将介绍Android系统加载so库的流程,以及部分原理,希望看完可以解答如下疑问:
1、APP 优先使用哪个文件夹的so库;
2、APP 自带的so库是怎么使用的;
3、系统是通过什么加载so库的;
 
先看一个整体流程图:
通过流程可知,load一个native库主要分两步:
1、查找到so库在哪里;
2、将查找到的so库之后通过JVM调用C库函数进行真正的加载
 
先分析它是如何找到so库的:
runtime.java的findLibrary函数最后是用的DexPathList的findLibrary函数:
 
 
 
element.findNativeLibrary(fileName) 继续根据名字查找对应的文件在哪个目录中 ,这个方法优先会去找非zipDir目录的library,然后再去
找zipDir目录的library,而这个zipDir 实际上就是APP原本的目录
 
 
请注意,findNativeLibrary这个方法是NativeLibraryElement类的方法,这个类的对象是element,而这个element是从nativeLibraryPathElements中来的,
弄清楚nativeLibraryPathElements 这个是从哪来的,接下来具体找哪个目录就会比较清楚了。
 
 
 
从上面函数可知,系统会优先查找自己目录的libraries,然后再找APK 压缩文件中,最后才会查找Android 虚拟机环境变量目录中的libraries,
同时,nativeLibraryPathElements是通过 makePathElements(getAllNativeLibraryDirectories()) 制造出来的,我们接着往下看:
 
 
 
 
这个函数的是通过传进来的参数getAllNativeLibraryDirectories() 来进行生成对应的NativeLibraryElement数组的,这个数组其实就是根据传来的文件路径再次进行组装分割,
而核心的分割方法就是通过这个符号:
private static final String zipSeparator = "!/";
这也就是为何我们会发现如果有APP找不到库时,会有一个这样奇怪的路径,其实就是在这个函数里面处理的,
再次看到如下相关的异常LOG之后就会比较亲切了:
 
 
我们再看看getAllNativeLibraryDirectories() 是怎么获取路径的:
 
private List<File> getAllNativeLibraryDirectories() {
List<File> allNativeLibraryDirectories = new ArrayList<>(nativeLibraryDirectories);
allNativeLibraryDirectories.addAll(systemNativeLibraryDirectories);
return allNativeLibraryDirectories;
 
 
这个获取路径就简单了,就是从nativeLibraryDirectories 里面来的,所以最终核心的关键是nativeLibraryDirectories 是从哪来的,仔细看代码会发现前面DexPathList进行对象
构造的时候,已经将其进行了赋值:
this.nativeLibraryDirectories = splitPaths(librarySearchPath, false);
其就是将librarySearchPath 里面的文件路径进行了分割存储到了nativeLibraryDirectories中,而librarySearchPath是从DexPathList 这个构造函数里面传入的,
那么是谁对DexPathList进行构造的就很关键了。
我们通过流程图倒回去看看,是BaseDexClassLoader 创建的DexPathList对象:
public BaseDexClassLoader(String dexPath,
String librarySearchPath, ClassLoader parent, ClassLoader[] sharedLibraryLoaders,
boolean isTrusted) {
super(parent);
// Setup shared libraries before creating the path list. ART relies on the class loader
// hierarchy being finalized before loading dex files.
this.sharedLibraryLoaders = sharedLibraryLoaders == null
? null
: Arrays.copyOf(sharedLibraryLoaders, sharedLibraryLoaders.length);
this.pathList = new DexPathList(this, dexPath, librarySearchPath, null, isTrusted);
 
if (reporter != null) {
reportClassLoaderChain();
}
}
 
而BaseDexClassLoader的 librarySearchPath也是传进来的。
 
文章来自个人专栏
Android系统开发
17 文章 | 1 订阅
0条评论
0 / 1000
请输入你的评论
0
0