大家好,我係蒼王。
以下是我這個系列的相關文章,有興趣可以參考一下,可以給個喜歡或者關注我的文章。
Replugin,為何我選擇要研究這個的外掛呢?很大的原因是因為它的介紹中說明,他只會有一個hook點。
一.Hook
hook點是什麼?
我們入門Android的時候,一定會看到過這個圖,但是你確定深刻了解到這個圖的嗎?
![[Android]用架構師角度看外掛化(2)-Replugin 唯一hook點](https://i.iter01.com/images/91eabff9fd5a258194ada64421ae891a33a5355fc2b4dd4a95244393ad2ae327.png)
我們試著換著思維,用元件化的角度去看這張圖,你會發現其層級依賴關係,與元件化的工程是非常類似的。(當然你看得角度不同,我只能說是類似)
倘若你用外掛的思想來看,我們上層的眾多應用(Applications)就是作為framewrok層的外掛一樣的存在。(Framework作為宿主一樣的存在,只是它是對於應用們,他說了算,基於安全管理和效率,他能限制你們獲取資源的許可權和方法)
然後我們想要在獨自的應用中做得像Framework層一樣的載入應用,我們本身就享用了Framework層對資源等的載入機制。如果我們想要將某些資源載入,載入驗證,許可權限制等繞開,運用到手機本身Framework來完成,就會涉及到hook了。
以我理解:hook,當Framework執行時,攔截並替換掉Framework層中某些原生的方法或物件,讓其執行到我們想要的效果。
滴滴的VirtualApk 會hook掉AMS(ActivityManagerService)和Instumentation,這兩個Framework的檔案非常重要,AMS是四大元件的入口,管理生命週期,管理應用通訊等,Instumentation管理了Activity的生命週期的呼叫。有興趣可以深入去看這兩個Framework檔案。而其他舊式外掛化,還會hook掉一下Service,Broadcast的機制。
而Replugin卻走的是完全和傳統外掛化不同的路,它hook掉的是ClassLoader,而且它只有唯一的hook點。
hook為何會不安全?
就是攔截和替換原生機制,因為Android的機型太多了,而且是開源的,那麼各個廠商定製Rom的修改,不同版本的適配也是非常大的阻礙,倘若替換掉某些廠商修改Google原生Android的原始碼裡面的方案,2️⃣剛好hook點沒有相容這方面的原始碼,就有引起hook失敗或者崩潰的可能性。
意味著hook點越少,其可能產生修改的程式碼會變小,維護的代價會變小,耗損的人力資源就會變少,整個使用者體驗就會提升。
架構的標準,是要懂得,衡量 時間+空間+效率。唯一hook點,暫時Replugin應該是外掛化hook點的極致了。
二.ClassLoader
對於Android 的ClassLoader,請認真仔細看下圖,一張圖為你解答各種疑問。
此圖非常形象的說明Android裡面ClassLoader的架構。
![[Android]用架構師角度看外掛化(2)-Replugin 唯一hook點](https://i.iter01.com/images/fb9a3625803469a9b6d99e2d3dfb8e8cbc38e717ba121df99a58c4e7012f1c3e.png)
這裡一般外掛化框架,都是使用DexClassLoader動態載入dex檔案。
DexClassLoader可以載入apk,dex,jar,還有zip字尾格式的檔案,其最終應該是載入dex檔案,這也是我QQ群中驗證問題的答案。
BaseDexClassLoader,裡面有一個DexPathList物件,是用來儲存dex的列表的,而查詢dex裡面的資源、class都是在這個列表中遍歷dex物件。
而Replugin是特別的其使用自定義的PathClassLoader來載入apk中的dex,其有別於其他外掛框架。
三.唯一hook點
我們看一下Replugin的載入過程。
用的是官網的replugin-host-library為例子
Application中attachBaseContext是最快執行的,其呼叫了Replugin.App.attachBaseContext方法
![[Android]用架構師角度看外掛化(2)-Replugin 唯一hook點](https://i.iter01.com/images/91a1107707f44ebd8131beb3def70140fce3a06a9091684f5a2b5436eb8ac45c.png)
他會呼叫到PMF這個類init方法,PMF是框架和住程式介面
![[Android]用架構師角度看外掛化(2)-Replugin 唯一hook點](https://i.iter01.com/images/8e370e1c612b7c8933705681c6ab9035bda0e472c2c3f167b92ce5575c269e6a.png)
其裡面會呼叫pluginManger的初始化,還有PatchClassLoaderUtils.patch的方法。
![[Android]用架構師角度看外掛化(2)-Replugin 唯一hook點](https://i.iter01.com/images/bd1969c5cbefa648bb4a075f58bf8fd2ac6e89db7399a623b043cae59286ca3a.png)
PatchClassLoaderUitls這個類是修改宿主和私有屬性的位置,其實就是那個唯一的hook點的位置
![[Android]用架構師角度看外掛化(2)-Replugin 唯一hook點](https://i.iter01.com/images/5be94de03ddeb2e3bda6cf56c1da8e36dec6c8018d7511e8b13a760128c96f32.png)
可以看到在patch中需要獲取到整個application的context物件。
![[Android]用架構師角度看外掛化(2)-Replugin 唯一hook點](https://i.iter01.com/images/338caf584aa5235368ad183f54f112b6e7c835ab58bbd40c7b318b4465cca6a5.png)
然後生成自己的classLoader物件,去hook掉mClassLoader物件,FieldUtils是對Java反射機制的封裝,以後使用到發射的時候,可以參考一下這裡的封裝,感覺是迄今看到眾多外掛化的封裝最完善的。
![[Android]用架構師角度看外掛化(2)-Replugin 唯一hook點](https://i.iter01.com/images/b0005e6cd9ec0b6b60cf6604d696fa6ad99a85abffb1f1b494219aace6311c5c.png)
這裡的對引數的說明很清晰,最終會返回RePluginClassLoader物件。
![[Android]用架構師角度看外掛化(2)-Replugin 唯一hook點](https://i.iter01.com/images/0529f4409ee78a3e902d606684f7e2762da82e3e458b698c251b5fc985942608.png)
![[Android]用架構師角度看外掛化(2)-Replugin 唯一hook點](https://i.iter01.com/images/49f5b1c5cf65260b748fdb9869896051a7441810605a205b0699db33665a8a5a.png)
這裡呼叫到RepluginClassLoader裡面,copyFromOrginal會將一些需要更改的屬性去掉final屬性,才能開始修改。initMethods,反射來替換掉ClassLoader的方法
![[Android]用架構師角度看外掛化(2)-Replugin 唯一hook點](https://i.iter01.com/images/afb25e33c3e865f6a8d260adcb872311305ae68a1e9b0aa41c5e6daa88a3a215.png)
裡面替換掉四個方法,findResource和findResources是資源的獲取,findLibrary是庫獲取,getPackage就是獲取包資訊了。
這裡MethodUtils是方法反射的封裝,也是封裝得非常好。
![[Android]用架構師角度看外掛化(2)-Replugin 唯一hook點](https://i.iter01.com/images/5dc33d993d749358c8f8b9489be43bc495b2ebec9da3b0b7cd65bf05bf1af7cf.png)
在Android原始碼中,是通過DexPathList中讀取資源,Resource是以URL格式返回,而lib庫是用String返回
![[Android]用架構師角度看外掛化(2)-Replugin 唯一hook點](https://i.iter01.com/images/44fbd6ba93d0423a38ba01e078b20754590fbf77237ecad10d0d4c23c8f2b330.png)
包獲取是在classLoader中完成的
![[Android]用架構師角度看外掛化(2)-Replugin 唯一hook點](https://i.iter01.com/images/1bd48a0393785c8685db61542a2f4b15cefd4d610467ae80fb7bf735213b5ec3.png)
這裡你會發現有點矛盾的地方,因為有可能不是那麼容易一下子能看明。
我們前面看到需要反射出一些BaseDexLoader的一些方法
![[Android]用架構師角度看外掛化(2)-Replugin 唯一hook點](https://i.iter01.com/images/3069a850eda099b19ef294081326664f04879a48e7358c5c2428e35d8724d867.png)
但是你看到其繼承呼叫的時候,卻使用了一模一樣的方法,這樣不就用了一模一樣的流程了?這有何意義?
![[Android]用架構師角度看外掛化(2)-Replugin 唯一hook點](https://i.iter01.com/images/05308fb95542a64fb585ba35b6acfac08f23f63345c558a181fc10ab8db0b74f.png)
這裡其實意義就在於其傳入的mOrig引數,這個引數是classLoader的物件,而不同外掛間都有classloader,那麼其分別呼叫外掛間的classloader資源的時候,就需要在這裡攔截呼叫。
以上就是對Replugin的唯一hook點的分析。
值得借鑑的地方。
(1)唯一hook點,是用hook掉足夠大的ClassLoader物件,來讓資源載入得到更加便利。
(2)Java反射機制的整合FieldUtils域反射封裝和MethodUtils方法反射封裝。
這裡發一條廣告,我創立了一個小密圈。
每天會分享java基礎,元件化外掛化相關,音視訊開源專案分享。在管理員們的努力下,提供了動腦學院vip,慕課網的Android付費資源。
最重要,帶有群員們珍貴的分析和點評。
還有最新外掛化框架的分析和運用,元件化架構技巧的分享,都盡在這裡。
不需要一頓飯的價錢 ,68/一整年的學習資料。
付費是真乾貨,真正節省時間的通往技術的途徑。
來到這裡希望影響你的不只是技術提升,而且是人生的架構的導向。
![[Android]用架構師角度看外掛化(2)-Replugin 唯一hook點](https://i.iter01.com/images/1b637ea86fa225ecd2820ae49ee46a5acad6af6c9e809f354c41b80ad742cae8.png)
成立兩週已經有超過190+的小夥伴加入了我們的行列了,並且持續增加,讓我們一起成長,群內還有不定時福利,包括原創書籍的福利哦。
![[Android]用架構師角度看外掛化(2)-Replugin 唯一hook點](https://i.iter01.com/images/2281beb9b7875c01ea14bebe9b78ac2b33596863e9f5e0352841e4a86c35f592.png)
我建立了一個關於Android架構學習的群,裡面可以進一步進行元件化學習的交流。
群號是316556016,也可以掃碼進群。我在這裡期待你們的加入!!!
![[Android]用架構師角度看外掛化(2)-Replugin 唯一hook點](https://i.iter01.com/images/b054d4146b8b0bbf9f8829ce1b4b5a77c03865c604656ce5c79d9c5d951a1832.png)