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的基础上添加或者修改其中的参数。