实现Android插件化的核心技术简介(一):Android dynamic load classes

实现Android插件化的核心技术(一): Android dynamic load classes

Android classes are loaded by DexClassLoader.

Android类由DexClassLoader加载

public class DexClassLoader extends BaseDexClassLoader {
    public DexClassLoader(String dexPath, String optimizedDirectory,
            String libraryPath, ClassLoader parent) {
        super(dexPath, new File(optimizedDirectory), libraryPath, parent);
    }
}

It was simply redirect to class BaseDexClassLoader.

转向BaseDexClassLoader

public BaseDexClassLoader(String dexPath, File optimizedDirectory,
        String libraryPath, ClassLoader parent) {
    super(parent);
    this.originalPath = dexPath;
    this.pathList =
        new DexPathList(this, dexPath, libraryPath, optimizedDirectory);
}

Let's track the dexPath, as usual, it's "/data/../*.apk", now it was used to create the pathList (DexPathList).

追踪下参数 dexPath,这个鬼通常是"/data/../*.apk",现用作创建pathList

public DexPathList(ClassLoader definingContext, String dexPath,
        String libraryPath, File optimizedDirectory) {
    ...
    this.dexElements =
        makeDexElements(splitDexPath(dexPath), optimizedDirectory);
    ...
}

And then dexElements ( DexPathList$Element[] ) was created.

再创建dexElements,注意下面代码里的 Archive File Loading Block,压缩包加载代码块

private static final String DEX_SUFFIX = ".dex";
private static final String JAR_SUFFIX = ".jar";
private static final String ZIP_SUFFIX = ".zip";
private static final String APK_SUFFIX = ".apk";
...
private static Element[] makeDexElements(ArrayList<File> files,
        File optimizedDirectory) {
    ArrayList<Element> elements = new ArrayList<Element>();
    /*
     * Open all files and load the (direct or contained) dex files
     * up front.
     */
    for (File file : files) {
        ZipFile zip = null;
        DexFile dex = null;
        String name = file.getName();
        if (name.endsWith(DEX_SUFFIX)) {
            // Raw dex file (not inside a zip/jar).
            ...
        } else if (name.endsWith(APK_SUFFIX) || name.endsWith(JAR_SUFFIX)
                || name.endsWith(ZIP_SUFFIX)) {
            //---------------------------------------------------
            // Archive File Loading Block
            // if (name.endsWith(".so") doFollowingWithReflect();
            //---------------------------------------------------
            try {
                zip = new ZipFile(file);
            } catch (IOException ex) {
                /*
                 * Note: ZipException (a subclass of IOException)
                 * might get thrown by the ZipFile constructor
                 * (e.g. if the file isn't actually a zip/jar
                 * file).
                 */
                System.logE("Unable to open zip file: " + file, ex);
            }
            try {
                dex = loadDexFile(file, optimizedDirectory);
            } catch (IOException ignored) {
                /*
                 * IOException might get thrown "legitimately" by
                 * the DexFile constructor if the zip file turns
                 * out to be resource-only (that is, no
                 * classes.dex file in it). Safe to just ignore
                 * the exception here, and let dex == null.
                 */
            }
        } else {
            System.logW("Unknown file type for: " + file);
        }
        if ((zip != null) || (dex != null)) {
            elements.add(new Element(file, zip, dex));
        }
    }
    return elements.toArray(new Element[elements.size()]);
}

By now, we can see that DexClassLoader only support files with extensions ".dex", ".jar", ".zip" and ".apk".

可以看到,DexClassLoader不支持".so"后缀

For support ".so" file which can be automatic built in android application storage, we needs to do stuff as Archive File Loading Block to create a DexPathList$Element and then reflect on host class loader and expand it's dexPathList's dexElements.

为了让应用启动时能自动复制插件包到应用存储目录,需要支持".so"后缀。做法就是模拟 压缩包加载代码块,创建一个dex元素,再反射添加到宿主class loader里的dexPathList。

Following is the fake code:

伪代码:

Context context = getApplicationContext();
File plugin = new File(context.getApplicationInfo().dataDir, "lib/**.so");
Element element = makeDexElement(plugin); // dalvik.system.DexPathList$Element
context.getClassLoader() // dalvik.system.DexClassLoader
        .@dexPathList // dalvik.system.DexPathList
        .@dexElements // dalvik.system.DexPathList$Element []
        .insert(element, 0);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值