Android資源篇2:從Activity啟動看AssetManager創建

導語 Android系統內部是在什么時候創建AssetManager,又是如何創建的? AssetManager與Resource什么關系? Android插件化為什么可以通過重寫addAssetPath方法訪問插件資源? 本文參考老羅的文章,并生成自己的見解,若有錯誤之處,懇請指正。 詳見:http://blog.csdn.net/luoshengyang/article/details/8791064

1、AssetManager與Resources

Android中的資源可以分為兩類:

  • 第一類資源,不對應文件的,如string資源;

  • 第二類資源,對應文件的,如layout資源。

  • 第一類資源只需通過資源ID查找到資源名稱即可,第二類資源需根據資源名稱打開相應文件。 通過下面這副圖片簡單的分析下資源查找的過程:


    ![2.png](https://upload-images.jianshu.io/upload_images/1986354-c116631c1d715cdd.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

如上圖所示,Resources根據資源ID查找資源,AssetManager根據資源名稱查找資源。若Resources查找資源時的資源ID對應的資源是文件,那先根據資源ID查找到資源文件名稱(在resources.arsc中查找到),再通過AssetManager打開相應文件。 看下Resources與AssetManager的成員變量:

  • ContextImpl提供接口getResources可以獲得指向當前APK資源的Resources對象。

  • Resouces類中的mAssets是AssetManager對象,用來訪問程序的非編譯文件(第二類資源);mSystem是Resources對象,用來訪問系統資源包,系統資源包存在/system/framework/framework-res.apk。

  • AssetManager(Java)中的sSystem是AssetManager對象,用來打開系統資源包文件;mObject是一個int地址,保存了對應C++層的AssetManager對象地址。

  • AssetManager(C++)中的mAssetPaths是資源目錄,mResources為資源表,mConfig保存了設備的本地配置信息。

2、Activity啟動

調用startActivity啟動指定Activity,最后會調用ApplicationThread的scheduleLaunchActivity方法。流程如下所示:

  1. scheduleLaunchActivity方法通過H發送消息H.LAUNCH_ACTIVITY

  2. H的消息處理中,調用ActivityThread的getPackageInfoNoCheck創建LoadedAPK對象,調用handleLaunchActivity啟動Activity。

  3. 創建的LoadedAPK對象指定資源路徑為當前APK。

  4. handleLaunchActivity啟動Activity,先調用makeApplication創建Application對象,并未Application關聯ContextImpl(baseContext)。

  5. 再為啟動的Activity關聯ComtextImpl(baseContext)。 該過程如下圖所示,其中AMS(ActivityManagerService)負責Activity聲明周期和Activity堆棧的管理,而ApplicationThread是App進程與AMS通信的Binder。ApplicationThread通過H(是一個Handler)實現與主線程ActivityThread的通信,進而管理者Activity的聲明周期。

3.png

在上過程中,首先會為創建的Application關聯AppContext,即為Application關聯ContextImpl;再為啟動的Activity關聯BaseContext,同樣為ContextImpl。該過程都會調用ContextImpl的構造方法,實現ContextImpl的創建,并調用init方法實現Resources、AssetManager的創建,那接著看ContextImpl的init過程。

(插一句,Application繼承ContextWrapper,ContextWrapper繼承Context;Activity繼承ContextThemeWrapper,ContextThemeWrapper繼承ContextWrapper。Application與Activity的基類Context是抽象類,其具有成員變量mBaseContext,采用代理模式,真正的操作都有mBaseContext實現。而真正實現Context方法的類只有ContextImpl,因此在創建Activity或Application都需要為其關聯一個ContextImpl對象)

3、ActivityManager創建

接著上一步的ContextImpl的創建,先看下時序圖:

4.png

該過程的主要實現了:


![6.png](https://upload-images.jianshu.io/upload_images/1986354-13db298d833ef0d6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

過程還是比較多的,挑幾步好好看下。

3.1、第1步:init

該步中調用LoadeAPk的getResources(..)方法獲得Resources對象,LoadedAPK在上面Activity啟動流程中進行創建(LoadedAPK保存了當前APK信息)。

6.png

3.2、第3步:getTopLevelResources

在第2步調用LoadedAPK的getResources方法中,它會調用ActivityThread的getTopLevelResources方法。該方法的主要內容有:


7.png

如上所示,該方法主要完成以下功能:

  1. 從Map緩存中取Resources對象,有直接返回,沒有下一步。

  2. 創建AssetManager,并接著添加系統資源文件路徑到資源目錄(mAssetPaths)中。

  3. 添加訪問的APK文件(當前APK文件)路徑到資源目錄(mAssetPaths)中。

  4. 創建Resources對象,并返回。

3.2、第7步:addAssetPath

在前面的分析中可知,通過調用addAssetPath方法將資源文件路徑添加到資源目錄中,實現資源的加載。該方法的主要內容有:

8.png

由上可知,addAssetPath主要是將資源文件路徑添加到資源目錄mAssetPaths中,并且判斷添加的apk文件是否位于/system/framework/下,如果是則會在/Vendor/overlay/frame/目錄下查找是否有同名的apk文件,有的話則用該apk文件覆蓋原有apk。(該機制一般用于廠商自定義資源覆蓋系統資源)。

4、總結

由上分析可知,ContextImpl創建過程中,會調研getResources()獲得Resources對象,而getResources最后調用getTopLevelResources方法。getTopLevelResources方法首先從緩存中拿Resources對象,沒有拿到則先創建AssetManager對象,并通過AssetManager的addAssetPath實現系統資源文件、當前APK資源文件的加載,然后再創建Resources對象返回。

5、后記

在andorid插件化機制中,關于如何訪問插件資源?,F在的一般做法是通過反射拿到AssetManager的addAssetPath方法,將插件資源路徑添加到資源目錄mAssetPath中,然后在創建Resources對象。

而另外一種方案則來自于DroidPlugin機制,該插件化機制采用Hook思想,當啟動插件Activity時,先替換啟動的插件Activity為代理Activity,再在H的消息處理中替換回插件Activity。而在H的消息處理中替換回插件Activity時,首先通過插件Acitivity信息創建LoadedAPK對象(指定資源路徑為插件路徑),再調用LoadedAPK的makeApplication創建插件Application。而關于makeApplication調用上面已經講過了,它會調用ContextImpl創建過程實現插件Resources的創建以及資源加載。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,517評論 6 539
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,087評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,521評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,493評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,207評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,603評論 1 325
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,624評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,813評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,364評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,110評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,305評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,874評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,532評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,953評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,209評論 1 291
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,033評論 3 396
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,268評論 2 375

推薦閱讀更多精彩內容