【Android 安全】DEX 加密 ( 多 DEX 加载 | 65535 方法数限制和 MultiDex 配置 | PathClassLoader 类加载源码分析 | DexPathList )
文章目錄
- 一、65535 方法數限制和 MultiDex 配置
- 二、多 DEX 加載引入
- 三、PathClassLoader 類加載源碼分析
- 四、BaseDexClassLoader 類加載源碼分析
- 五、DexPathList 相關載源碼分析
- 六、多 DEX 存放位置
一、65535 方法數限制和 MultiDex 配置
在 Android 開發中 , 尤其是項目比較大時 , 或引入的依賴庫過多 , 一般的項目后期都會遇到 如下問題 , 整個工程的方法數超過了 655356553565535 個 , 編譯時報如下錯誤 :
trouble writing output: Too many field references: 131000; max is 65536. You may try using --multi-dex option.Conversion to Dalvik format failed: Unable to execute dex: method ID not in [0, 0xffff]: 65536Google 官方給出了解決方案 : https://developer.android.google.cn/studio/build/multidex.html
5.05.05.0 之前的版本 , 應用中只能使用單個 classes.dex , 5.05.05.0 及以后的版本 原生支持多個 classes.dex 文件 ;
如果最低版本號大于等于 212121 , 就可以不用配置 MultiDex ;
反之版本號小于 212121 , 則 必須進行 MultiDex 配置 ;
Google 提供的 com.android.support:multidex 庫 , 就是為了兼容 5.05.05.0 之前的版本 ;
二、多 DEX 加載引入
MultiDexApplication 中就使用 Android 中的類加載機制 , ClassLoader 加載機制 ;
ClassLoader 相關源碼在 libcore/dalvik/src/main/java/dalvik/system Android 源碼目錄下 ,
參考 : libcore/dalvik/src/main/java/dalvik/system
常用的 ClassLoader 是 PathClassLoader 和 DexClassLoader ;
PathClassLoader 只能加載 已安裝 apk 的 dex ;
DexClassLoader 可以加載 已安裝 或 文件系統 中的 APK , DEX , JAR ;
源碼參考 :
- PathClassLoader : libcore/dalvik/src/main/java/dalvik/system/PathClassLoader.java
- DexClassLoader : libcore/dalvik/src/main/java/dalvik/system/DexClassLoader.java
三、PathClassLoader 類加載源碼分析
在 Android 中使用的是 PathClassLoader , 該類很簡單 , 只是單純的繼承 BaseDexClassLoader ,
package dalvik.system;public class PathClassLoader extends BaseDexClassLoader {public PathClassLoader(String dexPath, ClassLoader parent) {super(dexPath, null, null, parent);}public PathClassLoader(String dexPath, String libraryPath,ClassLoader parent) {super(dexPath, null, libraryPath, parent);} }參考源碼地址 : libcore/dalvik/src/main/java/dalvik/system/PathClassLoader.java
四、BaseDexClassLoader 類加載源碼分析
BaseDexClassLoader 是通過 Class<?> findClass(String name) 方法查找類的 , 給定一個全類名字符串 , 返回字節碼 ,
查找類通過調用 pathList 的 findClass 方法 , 獲取字節碼文件 ,
pathList 對應的成員變量定義是 DexPathList pathList , 它是 DexPathList 類型的 ,
public class BaseDexClassLoader extends ClassLoader {private final DexPathList pathList;@Overrideprotected Class<?> findClass(String name) throws ClassNotFoundException {List<Throwable> suppressedExceptions = new ArrayList<Throwable>();Class c = pathList.findClass(name, suppressedExceptions);if (c == null) {ClassNotFoundException cnfe = new ClassNotFoundException("Didn't find class \"" + name + "\" on path: " + pathList);for (Throwable t : suppressedExceptions) {cnfe.addSuppressed(t);}throw cnfe;}return c;} }參考源碼地址 : libcore/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java
五、DexPathList 相關載源碼分析
DexPathList 的 findClass 方法 , 主要是遍歷 Element[] dexElements 成員 ,
Element[] dexElements 數組中保存的就是內存中的 DEX 文件 , 如果 APP 中有 333 個 DEX 文件 , 那么該數組就有 333 個元素 ;
然后 獲取該 element 中的 dexFile , 這是 DexFile 類型文件 ,
調用 DexFile 的 loadClassBinaryName 加載對應的類 ,
/*package*/ final class DexPathList {/*** dex/resource (class path) 元素集合.* 應該調用 pathElements , 但是 Facebook 應用通過反射修改 dexElements .*/private final Element[] dexElements;public Class findClass(String name, List<Throwable> suppressed) {for (Element element : dexElements) {DexFile dex = element.dexFile;if (dex != null) {Class clazz = dex.loadClassBinaryName(name, definingContext, suppressed);if (clazz != null) {return clazz;}}}if (dexElementsSuppressedExceptions != null) {suppressed.addAll(Arrays.asList(dexElementsSuppressedExceptions));}return null;} }參考源碼地址 : libcore/dalvik/src/main/java/dalvik/system/DexPathList.java
六、多 DEX 存放位置
上述 DexPathList 中的 Element[] dexElements 成員就保存了當前應用中的 DEX 文件 ,
再次回到 classes.dex 分割的問題上 , 如果我們設置一個主 DEX , 其中只存在代理 Application , 用于解密其它被加密的 DEX , 其它的 DEX 都是被加密的 ;
這些 DEX 文件 都需要被存放到上述 DexPathList 的 Element[] dexElements 數組中 ;
總結
以上是生活随笔為你收集整理的【Android 安全】DEX 加密 ( 多 DEX 加载 | 65535 方法数限制和 MultiDex 配置 | PathClassLoader 类加载源码分析 | DexPathList )的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Android 安全】DEX 加密 (
- 下一篇: 【Android 安全】DEX 加密 (