AOSP Intent.getExtras的一個(gè)坑
注:非AOSP原生代碼已做脫敏處理
工作中做了一個(gè)需求,其中一部分是想把系統(tǒng)進(jìn)程里讀到的一些數(shù)據(jù),在應(yīng)用進(jìn)程啟動(dòng)Activity的時(shí)候去讀取。
大致流程是通過自定義接口讀到數(shù)據(jù)后傳入ActivityOptions,然后通過ActivityOptions在ActivityThread里傳給ActivityRecord里的Intent。通過AOSP的Intent.putExtras()放數(shù)據(jù),應(yīng)用進(jìn)程啟動(dòng)時(shí)通過Intent.getExtras()讀取。具體實(shí)現(xiàn)如下:
?ActivityStarter
AOSP代碼地址:https://android.googlesource.com/platform/frameworks/base/+/master/services/core/java/com/android/server/wm/ActivityStarter.java
Activity啟動(dòng)時(shí)通過execute()函數(shù)走到executeRequest()函數(shù),入?yún)equest類可以獲得Activity啟動(dòng)的一些信息request.activityOptions。

Activity的啟動(dòng)通過startActivityUnchecked,其中第一個(gè)參數(shù)r為ActivityRecord對(duì)象

r初始化過程中將checkedOptions作為入?yún)⒃O(shè)置為ActivityOptions

于是在初始化之前通過我的自定義接口返回帶有我自己數(shù)據(jù)的ActivityOptions
在https://android.googlesource.com/platform/frameworks/base/+/master/services/core/java/com/android/server/wm/ActivityStarter.java中加入接口調(diào)用
在啟動(dòng)Activity的時(shí)候,核心代碼是ActivityThread中的performLaunchActivity()方法

在大致3230行處,我試圖通過之前的ActivityOptions讀到數(shù)據(jù)
但是運(yùn)行App時(shí)獲得報(bào)錯(cuò),報(bào)錯(cuò)棧如下:
在intent.getExtras()報(bào)了ClassNotFoundException,猜測(cè)原因是App將自定義類的數(shù)據(jù)也放入了intent的mExtra中,但默認(rèn)ClassLoader不知道這個(gè)類,在intent.getExtras()時(shí)的反序列化報(bào)錯(cuò)。但是這說不通,因?yàn)锳pp本身是一定會(huì)知道自定義類的定義的,但在這里卻不知道了。后來繼續(xù)看performLaunchActivity的實(shí)現(xiàn)發(fā)現(xiàn):

performLaunchActivity會(huì)獲得App的ClassLoader并設(shè)置為mExtra的ClassLoader
https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/content/Intent.java

所以精簡(jiǎn)過程為:intent.getExtras()返回的mExtras是一個(gè)Bundle類,Bundle類的初始化需要對(duì)里面的所有數(shù)據(jù)反序列化。App塞入了一個(gè)自定義的類在intent的mExtras里,但我們?cè)讷@取mExtras的時(shí)候時(shí)機(jī)過早,Bundle還在使用系統(tǒng)默認(rèn)的ClassLoader而獲取不到相關(guān)自定義類的信息,導(dǎo)致ClassNotFoundException。而performLaunchActivity中會(huì)給mExtras做加載App的ClassLoader的操作。所以將代碼后移即可解決問題。這個(gè)想法也通過issuetracker得到了證實(shí):
https://issuetracker.google.com/issues/37053389

