Android runtime resource overlay
或許可以先看看
這位老兄Mårten Kongstad算是目前有比較完整再談 runtime resources overlay 的第一人
如果英文還行的話的可以直接看原文
硬要說的話最好有寫assetmanager 的概念,會比較理解這中間的原理
可以搭配老羅大師的幾篇文章(老羅真的很猛,可惜他的書有點舊了,不然還真想買一本)
http://blog.csdn.net/luoshengyang/article/details/8738877
正文開始
續前一篇 Android 實作 data/control 分離 – createPackageContext()
這種方法達到客製化的功能,再 android l 之後可以不用搞的那某麻煩
由sony 的團隊 提出一套新的 resources match framework.
Runtime Resource Overlay (RRO) ,sony 本身也同時利用於 Xperia Themes.
所以很明顯的 這就是要用在換圖片,背景之類的神兵利器.
Original Mechanism
Resources in Android consist of three parts:
-
A symbolic name – package.type/name, for example com.android.launcher.string/hello_world.
-
A set of configuration constraints that must not be violated if this resource’s value is to be used.
-
An actual value.
根據以上這些資訊 可以自動批配到最適合的機器狀況
flowchart TD
Start([取得當前設備 Configuration: 語系, 螢幕方向, DPI...]) --> Step1[1. 排除與當前設備約束衝突之候選目錄]
Step1 --> Step2[2. 依 Qualifier 優先權表鎖定最高優先維度: MCC/MNC -> 語系 -> 尺寸...]
Step2 --> Step3{是否存在包含該 Qualifier 的資源目錄?}
Step3 -- 是 --> Step4[3. 排除不含該 Qualifier 的其餘目錄]
Step3 -- 否 --> Step5[移至次高優先維度 Qualifier]
Step5 --> Step3
Step4 --> CheckSingle{是否僅剩單一最佳候選目錄?}
CheckSingle -- 否 --> Step5
CheckSingle -- 是 --> Match([完成最佳適配資源載入])
上述匹配規則這就不詳談了(看官網或老羅比較快),直接解釋底下這張圖片
sequenceDiagram
autonumber
actor App as Client App
participant AM as AssetManager
participant Target as Target APK (res/values)
participant FW as framework-res.apk (0x01)
App->>AM: getResources().getDrawable(0x7f020001)
AM->>Target: 1. 根據 Config (橫豎屏/DPI/語系) 查詢 Target APK
alt 命中資源
Target-->>AM: 返回對應 Drawable
else 系統資源 (0x01...)
AM->>FW: 2. 檢索系統 framework-res.apk
FW-->>AM: 返回系統原生 Drawable
end
AM-->>App: 完成資源載入
在android裡開發中常常用到的語法
context.getResources().getDrawable(R.id.hello_world);
這就是指定 resources 去取資料
接者此 resources id 資料會傳給 system 的 assetmanager, 利用 id+package name +機器的 configure(cfg)
進行最適合的資料批配(第一張圖),取得唯一的id值(0x7f),最後利用這值到apk拿出資源,至於左邊的 framework-res.apk 則是 android 提供的原生素材,資料等,可以發現resource id都是 0x01 開頭
就是利用這樣的機制,可以讓application 根據不同的機器狀態提供合適的資源,這也是為何大部分的ap開發者都會在res/底下設計不同的圖片資源或是語系對應,而在此之上,我想sony想要更加進一步,更彈性的提供這些資源去對應theme的對應,而不是在每次更新才提供新的樣貌,因此提出了新的runtime resources overlay的機制給google
以便在framework曾就把這些麻煩的外部資源access給作掉
How to use Runtime resource overlay
前面歷史講了那某多,其實用起來非常般單純,除了你本來就用被覆蓋的目標,以launcher為例,
(這是一個希望常常變更風格的app,或是想要客製化的部分)
一個專門overlay別人的ap,以下為必要的幾個要件
-
Have an AndroidManifest.xml.
-
May be installed.
-
Are built using aapt.
在AndroidManifest加入你想要覆蓋的對象
<overlay android:priority="2" android:targetPackage="com.example.android.launcher"/>
因為同時可能會有好幾個想要去overlay的ap(resources1.apk , resources2.apk),這時候系統就會去比對priority 值,越高的為越優先,如果沒有指定priority則以後安裝的為主,除了這樣,你想overlay的資源,必須跟對象擺在相同的對應路徑,且有相同的name.
Runtime resource overlay Mechanism
sequenceDiagram
autonumber
actor App as Client App
participant AM as AssetManager
participant OverlayHigh as Overlay 2 (/vendor/overlay/theme_b.apk, Priority=2)
participant OverlayLow as Overlay 1 (/vendor/overlay/theme_a.apk, Priority=1)
participant Target as Target APK (res/values)
App->>AM: getResources().getDrawable(0x7f020001)
critical 優先權鏈式檢索
AM->>OverlayHigh: 1. 優先查詢最高權重 Overlay (Priority=2)
alt 命中 Overlay 2
OverlayHigh-->>AM: 返回置換資源 (自訂佈景主題素材)
else 未命中
AM->>OverlayLow: 2. 依序降級查詢次權重 Overlay (Priority=1)
alt 命中 Overlay 1
OverlayLow-->>AM: 返回置換資源
else 未命中
AM->>Target: 3. 最後查詢 Target APK 原生資源
Target-->>AM: 返回原始素材
end
end
end
AM-->>App: 返回解析後的 Drawable
上述這張圖的路徑跟第二張圖蠻像的,就只差在找資源的時候會一個一個overlay的apk都去檢索一次,target apk是最後一個找的,其他多個overlay apk 則根據priority決定換上那一張圖
安全性呢?
這套功能感覺非常威猛,畢竟可以隨意亂覆蓋別人的ap資源,那不就代表可以惡搞別人的ap,像是 welcome , 改成shock的字串,其實這也沒那某容易,畢竟你要知道其他人的ap package name(雖然不難), 還有 id 對應name
(其實這也不難,畢竟decompile 都一堆人都在教了),上面我都說了一對不難了,難道google會覺得難嗎,所以他目前為了安全性,限制所有overlay apk,都會放在device的/vendor/overlay,而這個目錄一般開發者是沒辦法access的(至少要root)。
vendor們想要利用google play 的更新機制也必須確保是同個sign key,所以目前看起來,一般開發者還是不太能利用這樣的機制
總是有個極限
想要overlay的東西百百種,但是這機制也沒有那某厲害
-
至少要有個id吧,也就是說只要有id就有機會(integers, strings, drawable, arrays, and so on)
-
AndroidManifest.xml 這個不行(同上)
-
overlay reference 到其他的 reference(這很難解釋,等開下一篇)
try it.
最後你身為一個開發者,自己也去拉code,或者是同業去拉高通,發哥的code,然後也遵守上述的規則。發現還是沒有這機制,那請你一定先去確認overlay的id name 相關規則(我真的遇到很多人名子打錯)
如果還是沒問題,那應該就是code base 根本沒上這幾條patch
—-
runtime resources overlay patch
https://android-review.googlesource.com/#/c/113651/
https://android-review.googlesource.com/#/c/113652/
https://android-review.googlesource.com/#/c/113653/
https://android-review.googlesource.com/#/c/121589/
結束,下一篇考慮寫遇到的各種疑難雜症
ref:
發佈留言