I'm returning to an old topic, discussed a few times in the past:
https://groups.google.com/d/topic/android-framework/6ZdL1aQq8Qo/discussion
https://groups.google.com/d/topic/android-platform/1wFriR-6vOo/discussion
https://groups.google.com/d/topic/android-platform/eCVnMlQYjZc/discussion
https://groups.google.com/d/topic/android-platform/u4o3hNUqzec/discussion
At the time of those discussions, the conclusion was that there was no supported way for adding shared OEM resources.
However, now in the ICS (at least in 4.0.3) there is code, in frameworks/base/libs/utils/AssetManager.cpp, in AssetManager::addAssetPath(), that checks if the resource file that is being loaded starts with "/system/framework". If so, then after having loaded those resources, it loads any corresponding file at "/vendor/overlay/framework/". The resources are apparently added as an overlay to the resource being loaded, clearly augmenting the set of resources, but apparently also allowing one to override some existing resource values.
Now, given this, it looks like there is a way to add OEM shared resources!
In practical terms, and what we have tested in real life, it suffices to generate "another" framework-res.apk, place that at /vendor/overlay/framework/framework-res.apk, and the AssetManager will add the resources from that whenever it reads the /system/framework/framework-res.apk. It "just works".
Now, I'd like to know if this is a supported feature, at any level? Is it supposed to work, or is more that it just happens to work? Furthermore, is the feature likely to stay there in the AssetManager, or is it considered as a hack that may be removed at any time?
Finally, yes, we are fully aware of the problems of that shared resource IDs will cause to binaries and binary-level backwards compatibility. We do understand that Google cannot afford people setting their own shared resource IDs and assume that they can use those code points forever. However, given that what we are doing is essentially a prototype for a platform extension, we are more interested in doing a prototype that looks like a genuine platform extension, which may or may not be integrated to the Android proper, than providing something that can be used as an add-on for a long time.
--Pekka Nikander
PS. For those that are curios to see the details, here is what we have tested:
1. Android.mk for the <package>-res.apk and <package>.apk
In the Android.mk of the shared library, we create a separate target for <package>-res.apk. In that target, we set the following, as has been discussed earlier:
LOCAL_AAPT_FLAGS := -x
LOCAL_EXPORT_PACKAGE_RESOURCES := true
To install the <package>-res.apk as /vendor/overlay/network, we add the following definitions:
LOCAL_MODULE_PATH := $(TARGET_OUT)/vendor/overlay/framework
LOCAL_MODULE_STEM := framework-res
To resolve make dependency problems during a clean build, we further set (*after* including $(BUILD_PACKAGE)) the following:
$(resource_export_package): framework-res-package-target
For other packages that depend on our target, we set up a phony target:
.PHONY: <package>-package-target
<package>-package-target: $(LOCAL_BUILT_MODULE)
For the Java library compilation, we declare a name for the R.java file:
<package>_R_file_java := $(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),,COMMON)/src\
/$(subst -res,,$(subst .,/,$(LOCAL_PACKAGE_NAME)))/R.java
Then, in the target for the library itself (<package>.jar), we include the R.java from the resources:
LOCAL_INTERMEDIATE_RESOURCES += $(subst out/target/common/obj/,,$(<package>_R_file_java))
2. Providing shared resources
In the package itself, we have to declare which resources are public. For that, each time we add a new shared resource, we first compile the package once. Then, we copy the relevant new settings from
out/target/common/obj/APPS/<package>_intermediates/public_resources.xml
to
res/values/public.xml
That manual process takes care of what is actually shared, and what IDs they do get. That also avoids having resources to change their values in the future. (And this exactly is what causes the potential problems to Google, if this was a fully-supported feature, as anyone could start making their own shared IDs and assume the IDs to be fixed. I guess Google could set up a registration service, but given how the resource ID space is currently managed, it doesn't seem to be very scalable.)
Here is a complete (but edited) example of an Android.mk:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_PACKAGE_NAME := <package>-res # e.g. com.example.foo-res
LOCAL_MODULE_TAGS := optional
LOCAL_AAPT_FLAGS := -x
<package>_R_file_java := \
$(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),,COMMON)/src/$(subst -res,,$(subst .,/,$(LOCAL_PACKAGE_NAME)))/R.java
<package>_res_package_export := \
$(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),,COMMON)/package-export.apk
LOCAL_MODULE_PATH := $(TARGET_OUT)/vendor/overlay/framework
LOCAL_MODULE_STEM := framework-res
LOCAL_EXPORT_PACKAGE_RESOURCES := true
include $(BUILD_PACKAGE)
ifeq (,$(ONE_SHOT_MAKEFILE))
$(resource_export_package): framework-res-package-target
endif
.PHONY: <package>-res-package-target
<package>-res-package-target: $(LOCAL_BUILT_MODULE)
include $(CLEAR_VARS)
LOCAL_MODULE := <package> # e.g. com.example.foo
LOCAL_MODULE_TAGS := optional
LOCAL_CERTIFICATE := platform
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_JAVA_RESOURCE_DIRS :=
LOCAL_JAVA_RESOURCE_FILES :=
LOCAL_INTERMEDIATE_SOURCES += $(subst out/target/common/obj/,,$(<package>_R_file_java))
include $(BUILD_JAVA_LIBRARY)
$(full_classes_compiled_jar): <package>-res-package-target