mb612e2d70ec53f 2021-09-18 06:24:55 阅读数:860
圖中藍色的節點錶示注册服務的當前進程,也就是Server進程,紅色節點錶示Dispatcher進程。整個過程重點在第三步,我們再重點分析一下:
我們來看這個DispatcherProvider
接下來我們看服務的獲取,同樣的先看時序圖 ↓
1. Andromeda入口通過getRemoteService獲取遠程服務。2-4. 與提昇進程優先級有關,我們暫且不討論。5. 向RemoteTransfer請求獲取遠程服務的包裝bean。6-7. RemoteTransfer請求RemoteServiceTransfer幫忙先從本進程的緩存中查找目標Binder,如果找到直接返回。7.2. 如果沒有命中緩存調用getAndSaveIBinder方法,通過方法名可知,獲取後會將Binder緩存起來,這就是6-7步讀取的緩存。8. RemoteServiceTransfer通過DispatcherProxy發起IPC通信,請求遠程服務Binder。9-10. Dispatcher請ServiceDispatcher幫忙查找進程中的服務注册錶。11. 回到客戶端進程將Binder緩存。12. 將Binder返回給調用方。同樣圖中藍色的節點錶示獲取服務的進程,也就是Client進程,紅色節點錶示Dispatcher進程。至此,遠程服務的注册與獲取流程分析結束。
進程優先級上面提到在獲取遠程服務時,框架做了提昇進程優先級的事情。通常情况下使用遠程服務的端(簡稱Client端)處於前臺進程,而Server端進程已經注册完畢,往往處於後臺。為了提昇Server端的穩定性,最好能將Server端的進程優先級與Client保持接近,否則容易出現被LMK(Low Memory Killer)回收的情况。那如何提昇Server端進程的優先級呢?這裏的做法是用前臺的UI組件(Activity/Fragment/View)bind一個Server端預先插樁好的Service。整套流程最終通過AMS的updateOomAdjLocked方法實現。
回到Andromeda實現,這個預先插樁的Service如下:
複制代碼可見框架預置了15個Service供進程使用,也就是最多支持15個進程,這絕大數場景下足够了;另外維護了一個進程名和Service名稱的映射錶,否則怎麼知道應該bind那個Service,這個映射錶也是在編譯階段插樁完成的。 這個service的bind過程發生在上一章節獲取遠程服務時,流程如下圖:
圖中模塊根據所在進程分為三部分:
藍色錶示Client進程,發起獲取遠程服務請求。
淺灰色錶示Server進程,它事先將服務注册到Dispatcher中。
紫色錶示Dispatcher進程,內部緩存了各個進程的服務的Binder對象。
我們重點關注的是藍色模塊ConnectionManager部分,實際上當Client向Dispatcher請求遠程服務之後,會立即通過ConnectionManager綁定這個遠程服務所在進程的插樁的StubService,如此一來就提昇了Server所在進程的優先級。至此bind操作已經完成了,那何時unbind呢?顯然是當UI組件銷毀時,因為此時已不在前臺,需要降低進程優先級。如此一來就需要監聽UI組件的生命周期,在onDestroy時進行unbind操作。這就是圖中RemoteManager做的事情,它內部維護了前臺組件的生命周期。Andromeda提供了幾種with方法,用於獲取對應RemoteManager:
複制代碼這是借鑒Glide的做法,這些方法最終被轉換為兩類:
具備生命周期的UI組件,最終是Activity或Fragment。
ApplicationContext。
對於第一種情况,框架會為當前Activity或Fragment添加一個不可見的RemoteManagerFragment以監聽生命周期。對於使用ApplicationContext,獲取遠程服務的場景不做unbind操作。事實上用Jetpack lifecycle組件也可以方便的監聽Activity/Fragment的生命周期,但是這有個前提,那就是Activity必須繼承android.support.v4.app.FragmentActvity,而Fragment必須繼承android.support.v4.app.Fragment,且v4庫的版本必須大於等於26.1.0,從這個版本開始支持了Lifecycle。事件總線在上述通信框架基礎之上,實現事件總線簡直易如反指。我們來看一下使用。
這裏的Event是事件傳遞的載體。
至於原理,回想一下我們在注册遠程服務的過程中,同時將本進程的RemoteTransfer的Binder也注册到了Dispatcher中。 當我們訂閱一個事件時,只是將Event名稱和監聽器存儲在了本進程的RemoteTransfer中,當另一個進程發布事件時,會通過一次IPC調用將Event對象發送到Dispatcher,Dispatcher收到事件後,會向注册過的RemoteTransfer依次發送回調信息,也就是說這一步可能進行多次IPC調用,效率問題需diss一下。事件到達訂閱進程後會根據事件名稱,提取所有關於此名稱的監聽器,最終發送給監聽者。注意:這裏的監聽器常常使用的是Activity,但顯然RemoteTransfer是屬於進程生命周期的,因此保存監聽器時需使用弱引用。插樁上面分析原理過程中反複提到了插樁,總結一下共有幾處:
將屬於Dispatcher進程的DispatcherProvider和DispatcherService插入到manifest中(StubServiceGenerator)。
將各個進程的預置StubService插入到manifest中(StubServiceGenerator)。
將進程名與StubService的關系錶插入到StubServiceMatcher類的map中(StubServiceMatchInjector)。
對於manifest的操作,框架內提供了不少工具方法,比如獲取所有聲明的進程,值得好好學習一下;對於class的操作使用的是javasisst,這在之前的AOP文章中也介紹過,感興趣的同學自行查閱。在讀源碼過程中發現兩個值得關注的問題:一是DispatcherProvider偽造的DispatcherCursor繼承MatrixCursor,它通常用於返回幾條固定的已知記錄,不需要從數據庫查詢這種場景。二是跨進程傳遞bundle對象時,如果bundle中存放了parcelable對象需要手動設置setClassLoader。
因為默認情况下bundle傳輸使用的ClassLoader是BootClassLoader,而BootClassLoader只能加載系統類,我們本工程的class需要使用PathClassLoader進行加載,因此需要額外的調用bundle的setClassLoader方法設置類加載器。/? ?缺點? ?/
服務需要手動注册,這個時機不好把握。最好能提供一個自動注册服務的開關,上層不需要關注服務的注册。
發送一次事件需要多次IPC調用效率低,有優化空間。
仍需要書寫AIDL文件。
至此,Andromeda核心的原理我們就分析完了,雖然有些問題有待完善,但已經給我們提供了很多優秀的解决問題的思路,無論是繼續優化還是精簡一下本地化都是不錯的選擇。
[阿裏P6P7【安卓】進階資料分享+加薪跳槽必備面試題](
)
那麼對於想堅持程序員這行的真的就一點希望都沒有嗎?
其實不然,在互聯網的大浪淘沙之下,留下的永遠是最優秀的,我們考慮的不是哪個行業差哪個行業難,就逃避掉這些,無論哪個行業,都會有他的問題,但是無論哪個行業都會有站在最頂端的那群人。我們要做的就是努力提昇自己,讓自己站在最頂端,學曆不够那就去讀,知識不够那就去學。人之所以為人,不就是有解决問題的能力嗎?擋住自己的由於只有自己。
Android希望=技能+面試
CodeChina開源項目地址:《Android學習筆記總結+移動架構視頻+大廠面試真題+項目實戰源碼》
版权声明:本文为[mb612e2d70ec53f]所创,转载请带上原文链接,感谢。 https://gsmany.com/2021/09/20210918062454907w.html