android資原始檔overlay
aapt
aapt stands for Android Asset Packaging Tool. This tool is part of the SDK (and build system) and allows you to view, create, and update Zip-compatible archives (zip, jar, apk). It can also compile resources into binary assets.
aapt在android中主要打包資原始檔等,在definitions.mk中,aapt使用了-S PRIVATE_RESOURCE_DIR
PRIVATE_RESOURCE_DIR := $(LOCAL_RESOURCE_DIR)
,所以資原始檔都包含在LOCAL_RESOURCE_DIR
中。
// build\core\definitions.mk
# This rule creates the R.java and Manifest.java files, both of which
# are PRODUCT-neutral. Don't pass PRIVATE_PRODUCT_AAPT_CONFIG to this invocation.
define create-resource-java-files
@mkdir -p $(PRIVATE_SOURCE_INTERMEDIATES_DIR)
@mkdir -p $(dir $(PRIVATE_RESOURCE_PUBLICS_OUTPUT))
$(hide) $(AAPT) package $(PRIVATE_AAPT_FLAGS) -m \
$(eval # PRIVATE_PRODUCT_AAPT_CONFIG is intentionally missing-- see comment.) \
$(addprefix -J , $(PRIVATE_SOURCE_INTERMEDIATES_DIR)) \
$(addprefix -M , $(PRIVATE_ANDROID_MANIFEST)) \
$(addprefix -P , $(PRIVATE_RESOURCE_PUBLICS_OUTPUT)) \
$(addprefix -S , $(PRIVATE_RESOURCE_DIR)) \
$(addprefix -A , $(PRIVATE_ASSET_DIR)) \
$(addprefix -I , $(PRIVATE_AAPT_INCLUDES)) \
$(addprefix -G , $(PRIVATE_PROGUARD_OPTIONS_FILE)) \
$(addprefix --min-sdk-version , $(PRIVATE_DEFAULT_APP_TARGET_SDK)) \
$(addprefix --target-sdk-version , $(PRIVATE_DEFAULT_APP_TARGET_SDK)) \
$(if $(filter --version-code,$(PRIVATE_AAPT_FLAGS)),,$(addprefix --version-code , $(PLATFORM_SDK_VERSION))) \
$(if $(filter --version-name,$(PRIVATE_AAPT_FLAGS)),,$(addprefix --version-name , $(PLATFORM_VERSION))) \
$(addprefix --rename-manifest-package , $(PRIVATE_MANIFEST_PACKAGE_NAME)) \
$(addprefix --rename-instrumentation-target-package , $(PRIVATE_MANIFEST_INSTRUMENTATION_FOR))
endef
-S 引數用來指定資原始檔,搜尋多個目錄,從左到右,找到第一個匹配的。
-S directory in which to find resources. Multiple directories will be scanned
and the first match found (left to right) will take precedence.
overlay的是資源
關於android中資源的定義在http://developer.android.com/guide/topics/resources/index.html中有詳細的介紹,而overlay的主要作用就是為了替換apk中的資原始檔(隨便定義一個txt,並不能算資原始檔),例如,frameworks\base\core\res\res\values\strings.xml中就定義了很多framework中需要用到的資源(resources ,string),假設其中有4條資源,
//frameworks\base\core\res\res\values\strings.xml
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="byteShort">B</string>
<string name="kilobyteShort">KB</string>
<string name="megabyteShort">MB</string>
<string name="gigabyteShort">GB</string>
</resources>
在開發中,可以在其他地方定義PRODUCT_PACKAGE_OVERLAYS,新建一個strings.xml,修改其中的某個資源的的屬性值,
// 其他overlay目錄\frameworks\base\core\res\res\values\strings.xml
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="gigabyteShort">gb</string>
</resources>
這樣編譯完成後,gigabyteShort會變成修改後的值,其他3個值不變。
// overlay後的資原始檔
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="byteShort">B</string>
<string name="kilobyteShort">KB</string>
<string name="megabyteShort">MB</string>
//這條變化了
<string name="gigabyteShort">gb</string>
</resources>
在這裡overlay替換的是資源,而不是檔案。所以即使新建的string.xml中僅有1條修改,最終編譯後的資原始檔中其他3條保持不變。
預設情況下,overlay目錄的資原始檔內容只能覆蓋原有軟體包中的資源,而不能新增資源。不然會造成編譯錯誤。
但是也有2種方法規避:
1.原資原始檔中也新增上該資源(這樣就不算新增了),
2.一種更加簡便的方法是給aapt命令增加–auto-add-overlay選項。
overlay的也可能是檔案
最近在修改frameworks\base\core\res\res\xml\power_profile.xml中電池總電量的數值,將battery.capacity修改為3500mA,下面是對應的overlay檔案,只添加了一條。
<device name="Android">
<item name="battery.capacity">3500</item>
</device>
但是修改完成後發現問題,設定—電池—上次充滿後的電量使用情況一直是沒有電池使用情況。檢視相關程式碼發現,
只有在power_profile.xml中的screen.full大於10才會去refresh電量使用情況。
// packages\apps\Settings\src\com\android\settings\fuelgauge\PowerUsageSummary.java
private void refreshStats() {
final PowerProfile powerProfile = mStatsHelper.getPowerProfile();
final BatteryStats stats = mStatsHelper.getStats();
// power profile就是上面的power_profile.xml
// screen.full
final double averagePower = powerProfile.getAveragePower(PowerProfile.POWER_SCREEN_FULL);
// MIN_AVERAGE_POWER_THRESHOLD_MILLI_AMP = 10;
// screen.full所對應的值必須大於10才會去refresh電量使用情況
if (averagePower >= MIN_AVERAGE_POWER_THRESHOLD_MILLI_AMP) {
...........
}
if (!addedSome) {
addNotAvailableMessage();
}
BatteryEntry.startRequestQueue();
}
而out目錄下生成的資原始檔中,power_profile.xml只有battery.capacity這一條(沒有對應的screen.full這條,所以才不會去顯示電量使用情況),所以這時候也可以說是檔案覆蓋了,仔細檢視原power_profile.xml中的內容,發現其格式並不是android所規定的資原始檔,而是一個特殊的xml檔案,這時候就不是overlay資源了,而是類似於替換檔案。
同時檢視frameworks\base\core\res\res\xml\power_profile.xml原生的引數值,發現screen.full為0.1,也不是大於10,為何在沒新增power_profile.xml這個overlay檔案時,功能一切正常?
<item name="screen.full">0.1</item>
搜尋整個程式碼(高通8939平臺),發現DEVICE_PACKAGE_OVERLAYS中有對power_profile.xml的overlay,其中是高通自己定義的一些電池的引數,其中screen.full為261。
// device\qcom\msm8916_64\msm8916_64.mk
DEVICE_PACKAGE_OVERLAYS := device/qcom/msm8916_64/overlay
那麼既然高通本身有對power_profile.xml的overlay,自己新增的overlay將高通的覆蓋了?在package_internal.mk中,
// build\core\package_internal.mk中
// PRODUCT_PACKAGE_OVERLAYS排在DEVICE_PACKAGE_OVERLAYS前面,
// 所以PRODUCT_PACKAGE_OVERLAYS 優先於 DEVICE_PACKAGE_OVERLAYS
package_resource_overlays := $(strip \
$(wildcard $(foreach dir, $(PRODUCT_PACKAGE_OVERLAYS), \
$(addprefix $(dir)/, $(LOCAL_RESOURCE_DIR)))) \
$(wildcard $(foreach dir, $(DEVICE_PACKAGE_OVERLAYS), \
$(addprefix $(dir)/, $(LOCAL_RESOURCE_DIR)))))
LOCAL_RESOURCE_DIR := $(package_resource_overlays) $(LOCAL_RESOURCE_DIR)
從上面可以看出,PRODUCT_PACKAGE_OVERLAYS 優先於 DEVICE_PACKAGE_OVERLAYS,而aapt -S會從左到右搜尋資原始檔,所以PRODUCT_PACKAGE_OVERLAYS中定義的會優先被匹配。
所以最終的修改方法是:
1.將高通DEVICE_PACKAGE_OVERLAYS中的power_profile.xml拷貝一份到自己的overlay目錄中(電池等的引數,不同的裝置廠商的引數不同,因此以裝置廠商的為準,而不用原生的power_profile.xml),
2.在此power_profile.xml的基礎上新增或者修改其中的引數。