官方multidex的加载过程分析然后研究研究能否抄袭一点点技术

1、检测jvm版本,正则 2.1.0 那么就是支持jvm,那么默认是不是进行dex的合并。
. doInstallation方法获取到了ApplicationInfo

mainContext: Context  = {AppContext@4800} 
sourceApk: File  = {File@4821} "/data/app/cn.qssq666.robot-2/base.apk"
dataDir: File  = {File@4822} "/data/user/0/cn.qssq666.robot"
secondaryFolderName: String  = {@4823} "secondary-dexes"
prefsKeyPrefix: String  = {@4824} ""

2、clearOldDexDir第二步检查包名/files/secondary-dexes/是否存在存在则删除。里面所有文件,还把文件夹也删除了.
. /data/user/0/cn.qssq666.robot/code_cache/secondary-dexes

检查是否更改,更改就走另外一个方法否则走performExtractions
大概逻辑是读取apk的classdex 2-最终的dex全部打包(extract方法打包)成zip文件
如先把classes2.dex解压打包成临时文件
/data/user/0/cn.qssq666.robot/code_cache/secondary-dexes/tmp-base.apk.classes238553433.zip
然后重命名为为/data/user/0/cn.qssq666.robot/code_cache/secondary-dexes/base.apk.classes2.zip

打包的代码分析

InputStream in = apk.getInputStream(dexFile);
        ZipOutputStream out = null;
        File tmp = File.createTempFile("tmp-" + extractedFilePrefix, ".zip", extractTo.getParentFile());
        Log.i("MultiDex", "Extracting " + tmp.getPath());

        try {
            out = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(tmp)));

            try {
                ZipEntry classesDex = new ZipEntry("classes.dex");
                classesDex.setTime(dexFile.getTime());
                out.putNextEntry(classesDex);
                byte[] buffer 

从zipentry实体获取entry的输入流然后创建一个ZipOutputStream输出流,然后给他弄一个时间,然后zip的实体名字叫classes.dex也就是每一个zip文件都有一个classes.dex很显然,他的合并技术和我用的方法完全不同。是把一个包含多个dex的apk变成每一个apk,(当然这里叫zip)然后里面有一个classes.dex

image.png

最终的成果


image.png

然后
/data/user/0/cn.qssq666.robot/shared_prefs/multidex.version.xml
把时间戳和zip的crc校验码存起来


    private static void putStoredApkInfo(Context context, String keyPrefix, long timeStamp, long crc, List<MultiDexExtractor.ExtractedDex> extractedDexes) {
        SharedPreferences prefs = getMultiDexPreferences(context);
        Editor edit = prefs.edit();
        edit.putLong(keyPrefix + "timestamp", timeStamp);
        edit.putLong(keyPrefix + "crc", crc);
        edit.putInt(keyPrefix + "dex.number", extractedDexes.size() + 1);
        int extractedDexId = 2;

        for(Iterator var10 = extractedDexes.iterator(); var10.hasNext(); ++extractedDexId) {
            MultiDexExtractor.ExtractedDex dex = (MultiDexExtractor.ExtractedDex)var10.next();
            edit.putLong(keyPrefix + "dex.crc." + extractedDexId, dex.crc);
            edit.putLong(keyPrefix + "dex.time." + extractedDexId, dex.lastModified());
        }

        edit.commit();
    }

这才完成了

   List<? extends File> files = MultiDexExtractor.load(mainContext, sourceApk, dexDir, prefsKeyPrefix, false);
                  

的逻辑
然后走
installSecondaryDexes(loader, dexDir, files);

具体逻辑

    }

    private static final class V19 {
        private V19() {
        }

        private static void install(ClassLoader loader, List<? extends File> additionalClassPathEntries, File optimizedDirectory) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, InvocationTargetException, NoSuchMethodException {
            Field pathListField = MultiDex.findField(loader, "pathList");
            Object dexPathList = pathListField.get(loader);
            ArrayList<IOException> suppressedExceptions = new ArrayList();
            MultiDex.expandFieldArray(dexPathList, "dexElements", makeDexElements(dexPathList, new ArrayList(additionalClassPathEntries), optimizedDirectory, suppressedExceptions));
            if (suppressedExceptions.size() > 0) {
                Iterator var6 = suppressedExceptions.iterator();

                while(var6.hasNext()) {
                    IOException e = (IOException)var6.next();
                    Log.w("MultiDex", "Exception in makeDexElement", e);
                }

                Field suppressedExceptionsField = MultiDex.findField(dexPathList, "dexElementsSuppressedExceptions");
                IOException[] dexElementsSuppressedExceptions = (IOException[])((IOException[])suppressedExceptionsField.get(dexPathList));
                if (dexElementsSuppressedExceptions == null) {
                    dexElementsSuppressedExceptions = (IOException[])suppressedExceptions.toArray(new IOException[suppressedExceptions.size()]);
                } else {
                    IOException[] combined = new IOException[suppressedExceptions.size() + dexElementsSuppressedExceptions.length];
                    suppressedExceptions.toArray(combined);
                    System.arraycopy(dexElementsSuppressedExceptions, 0, combined, suppressedExceptions.size(), dexElementsSuppressedExceptions.length);
                    dexElementsSuppressedExceptions = combined;
                }

                suppressedExceptionsField.set(dexPathList, dexElementsSuppressedExceptions);
            }

        }

        private static Object[] makeDexElements(Object dexPathList, ArrayList<File> files, File optimizedDirectory, ArrayList<IOException> suppressedExceptions) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
            Method makeDexElements = MultiDex.findMethod(dexPathList, "makeDexElements", ArrayList.class, File.class, ArrayList.class);
            return (Object[])((Object[])makeDexElements.invoke(dexPathList, files, optimizedDirectory, suppressedExceptions));
        }
    }
}

很遗憾,这个v19的代码在我的23的手机并不能执行,
因为PathClassloader没有makeDexElements方法。

这里就不继续探索了,看看源码有哪几个把,copy过来改一下看看

image.png

首先要让IS_VM_MULTIDEX_CAPABLE变成非常量,这样才好玩嘛。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容