當前位置:首頁 » 安卓系統 » loaderandroid

loaderandroid

發布時間: 2023-07-27 05:02:10

A. android插件化(四)Hook載入插件APK(ClassLoader方式)

前面插件化一和二說了下插樁式載入未安裝的APK,主要是重寫了getResource和getClassloader兩個方法來實現的。以及每個組件要實現一個介面,通過介面注入上下文來達到它的生命周期。

那麼插樁式和hook式的實現方式有什麼不同呢?

插樁式是怎麼載入到插件中的class文件呢,是通過將將APK轉化成插件的Classloader,然後想要載入插件的class文件,我們的去拿這個插件的classloader去loadClass。所以是有一個中間者的。

hook式呢是將插件apk融入到了我們的宿主apk,那直接在裡面就可以直接loadClass了,在不用這個插件的ClassLoader了,這樣的話對於插件和宿主就沒什麼區別了,不像插樁式有一個中間者。

那麼要實現hook式 就要知道android中一個class文件式怎樣被載入到內存中去的。其實就是通過PathClassLoader來載入的。

那麼我們先看下ClassLoader

任何一個java程序都是由一個或者多個class組成的,在程序運行時,需要將class文件載入到JVM中才可以使用,負責載入這些class文件的就是java的類載入機制。CLassLoader的作用就是載入class文件提供給程序運行時使用,每個Class對象內部都有一個ClassLoader來標示自己是有那個classLoade載入的。

Android app的所有的java文件都是通過PathClassLoader來載入的,那麼它的父類是BaseDexClassLoader,還有一個兄弟類是DexClassLoader,那麼他們有什麼區別呢。

從上面可以看出這兩個類的構造函數不同。(在26的源碼中DexClassLoader中的optimizedDirectory也廢棄了)

PathClassLoader:用於Android應用程序類載入器。可以載入指定的dex,以及jar、zip、apk中的classes.dex

DexClassLoader:載入指定的dex以及jar、zip、apk中的classes.dex。

可以看到創建ClassLoader的時候需要接收一個CLassLoader parent的參數,這個parent的目的就在於實現類載入的委託。

某個類載入器在接到載入類的請求時,首先將載入任務委託給父類載入器,一次遞歸,如果父載入器可以完成載入任務,那麼就返回,只有當父載入器無法完成載入任務時,才自己去載入。

因此我們自己創建的ClassLoader:newPathClassLoader("/sdcard/xx.dex",getClassLoader()),並不僅僅只能載入我們的xx.dex中的class。

需要注意的是,findBootstrapClassOrNull 這個方法,當parent為null的時候,去這個BootCLassLoader進行載入,

但是在Android當中的實現:

所以new PathClassLoader("/sdcard/xx.dex",null),是不能載入Activity.class的。

上面分析了載入了一個class,是利用了雙親委託機制,那麼要是都找不到那就開始調用自己的findCLass方法

在ClassLoader類中findClass:

任何ClassLoader的子類,都可以重寫loadClass和findClass。如果你不想使用雙親委託,就重寫loadClas修改實現,重寫findClass則表示在雙親委託機制下,父ClassLoader都找不到class的情況下,定義自己去查找一個class。

而我們的PathClassLoader會自己負責載入Activity這樣的類,利用雙親委託父類去載入activity,而我們的PathClassLoader沒有重寫findClass,是在它的父類裡面。因此我們可以看看父類的findClass是如何實現的。

可以看到載入PathClassLoader載入class,轉化為從DexPathList中載入class了,那麼我們看看DexPathList中的findClass

那麼從上面分析得到

到這里我們想要載入一個插件的apk ,其實最終載入的是一個dex文件(先說class文件,載入資源後面說),有沒有辦法吧這個dex文件給轉化成一個 Element 對象,給放到 Elemeng數組 當中,這樣直接就可以載入我們插件中的類了。

1、首先我們肯定是要得到插件APK的的中DexPathList對象中的dexElement數組

2、插件的dexElements數組我們拿到了,那麼是不是要開始拿我們系統裡面的 ,我們反射獲取,和上面的一樣。

3、上面我們獲取到了系統和我們插件的dexElement數組,然後我們將這個數組合並到一個新的數組裡面去,並且給注入到系統裡面

至此,載入插件的一個流程基本就完成了。但是上面只是處理了class文件,沒有處理資源。資源的話我們也是採用hook的方式去實現

在宿主的Application中hook這個方法,然後去重寫getAsserts和getResources兩個方法:

然後在插件的BaseActivity中繼續重寫getAssets和getResources兩個方法

這樣就可以完成hook式載入一個未安裝的APK了。至此基本就完成了插樁式和Hook式插件化的基本實現。(後面幾篇是優化)。

B. 【Android】Android中的類載入

前文: 【Java】ClassLoader與雙親委派機制

Android中的類載入器有三種, DexClassLoader 、 PathClassLoader 、 BootClassLoader 。
其中 BootClassLoader 是系統啟動時預載入常用類的,一般使用不到。 DexClassLoader 、 PathClassLoader 都是繼承自 BaseDexClassLoader 。
但 DexClassLoader 和 PathClassLoader 並沒有重寫 BaseDexClassLoader 中的任何方法,所以源碼只需要看 BaseDexClassLoader 即可。

由於Android SDK並沒有包含 BaseDexClassLoader ,所以需要到源碼查詢網站查詢源碼,如下:

復制這個java文件到對應源碼文件夾下就可以在Android Studio中查看了。

通過調試可以看到,Android中普通類的載入器其實是 PathClassLoader 。追蹤 PathClassLoader.findClass 方法,即可獲取Android的類載入過程:

PathClassLoader.findClass -- 繼承自 --> BaseDexClassLoader.findClass()
-> BaseDexClassLoader.pathList.findClass()
-> DexPathList.dexElements.foreach { element.findClass() }
-> Element.findClass()
-> Element.dexFile.loadClassBinaryName()
-> DexFile.defineClass()

即類載入過程通過 BaseDexClassLoader.findClass 、 DexPathList.findClass 、 Element.findClass 、 DexFile.loadClassBinaryName ,最終會落到 DexFile.defineClass 方法中,然後就交給native層了。

其中需要注意的是,在 BaseDexClassLoader.findClass 的開頭有這么一段:

這段是在Android 10新加入的,據稱是為了實現 shared library 功能的,在之前的版本中沒有這一段。

在上一節中知道了,類載入的流程如下:
BaseDexClassLoader.findClass() ->
BaseDexClassLoader.pathList.findClass() ->
DexPathList.dexElements.foreach { element.findClass() } ->
Element.findClass() -> ...

看 DexPathList.findClass 方法:

可以發現, DexPathList 載入類的方法是遍歷 dexElements 數組依次載入,知道獲取到值為止。所以可以通過修改這個數組,把新的dex文件放在數組的前面,使其載入修改後的類,從而實現熱修復。

根據以上原理,寫下這個工具類,有效性待驗證:

熱點內容
安卓哪裡填寫apple代碼 發布:2025-02-05 00:28:54 瀏覽:287
oppo手機鎖屏密碼忘記後如何更換 發布:2025-02-05 00:28:19 瀏覽:25
幼兒思維編程 發布:2025-02-05 00:18:21 瀏覽:25
我的世界電腦正版如何進入伺服器 發布:2025-02-05 00:18:06 瀏覽:880
疫情防控健康碼預警機制演練腳本 發布:2025-02-04 23:58:46 瀏覽:39
分治演算法java 發布:2025-02-04 23:41:15 瀏覽:593
安卓app點進去就閃退怎麼回事 發布:2025-02-04 23:36:56 瀏覽:779
宏按鍵編程 發布:2025-02-04 23:05:11 瀏覽:904
微信隱形密碼在哪裡設置 發布:2025-02-04 23:05:01 瀏覽:866
android的補間動畫 發布:2025-02-04 23:03:42 瀏覽:416