Android SO库的加载过程

首先是Java层的调用,直接使用系统提供的接口:

System.loadLibrary("name");

我们跟踪一下源码可以知道,它是直接调用Runtime.getRuntime()的loadLibrary

/**
     * Loads the system library specified by the <code>libname</code>
     * argument. The manner in which a library name is mapped to the
     * actual system library is system dependent.
     *
     * @param      libname   the name of the library.
     * @exception  SecurityException  if a security manager exists and its
     *             <code>checkLink</code> method doesn't allow
     *             loading of the specified dynamic library
     * @exception  UnsatisfiedLinkError  if the library does not exist.
     * @exception  NullPointerException if <code>libname</code> is
     *             <code>null</code>
     * @see        java.lang.Runtime#loadLibrary(java.lang.String)
     * @see        java.lang.SecurityManager#checkLink(java.lang.String)
     */
    public static void loadLibrary(String libname) {
        Runtime.getRuntime().loadLibrary0(VMStack.getCallingClassLoader(), libname);
    }

然后是看一下Runtime类的loadLibrary方法:

void loadLibrary(String libraryName, ClassLoader loader) {
            if (loader != null) {
                //[见小节2.4]
                String filename = loader.findLibrary(libraryName);
                if (filename == null) {
                    throw new UnsatisfiedLinkError(...);
                }
                //成功执行完doLoad,则返回
                String error = doLoad(filename, loader);
                if (error != null) {
                    throw new UnsatisfiedLinkError(error);
                }
                return;
            }
            //当loader为空的情况下执行
            String filename = System.mapLibraryName(libraryName);
            List<String> candidates = new ArrayList<String>();
            String lastError = null;

            //此处的mLibPaths取值
            for (String directory : mLibPaths) {
                String candidate = directory + filename;
                candidates.add(candidate);

                if (IoUtils.canOpenReadOnly(candidate)) {
                    String error = doLoad(candidate, loader);
                    if (error == null) {
                        return; //成功执行完doLoad,则返回.
                    }
                    lastError = error;
                }
            }

            if (lastError != null) {
                throw new UnsatisfiedLinkError(lastError);
            }
            throw new UnsatisfiedLinkError("Library " + libraryName + " not found; tried " + candidates);
        }
    }

将中的参数名还原成带“lib”前缀的名字:

public static String mapLibraryName(String nickname) {
    if (nickname == null) {
        throw new NullPointerException("nickname == null");
    }
    return "lib" + nickname + ".so";
}

如何classloader为空,则会通过BaseDexClassLoader把dex文件加载进来,从而找到相应的so库文件路径。

最后会调用到Runtime类的的一个native方法nativeLoad(),之后就交由native层去加载so库了。

native层中是调用JavaVMExt类的LoadNativeLibrary()函数来加载.so文件的,系统加载so,在完成装载、映射和重定向以后,就首先执行.init和.init_array段的代码,之后如果存在JNI_OnLoad就调用该函数,LoadNativeLibrary()函数执行的主要流程为:

  • (1)判断该.so文件是否已经加载了,如果已经加载了,检查 class_loader是否一样;
  • (2)如果没有加载,调用dlopen()函数加载该.so文件;
  • (3)调用dlsym()找到JNI_OnLoad函数的地址;
  • (4)调用JNI_OnLoad函数。

至此,一个.so文件就加载完成了。so文件加载到内存并链接完成后,就开始调用so中的初始化函数。

详细说明文章:

loadLibrary动态库加载过程分析

文章目录
|