Just recently, a new framework called Runtime Resource Overlay (RRO) was contributed by Sony to the Android code base. This framework provides the ability to replace application resources while the application is running, we currently use RRO for device customisation and to support Xperia Themes. In this article, Mårten Kongstad, Lead Developer of Runtime Resource Overlay, explains this new framework in detail.
Mårten Kongstad, Lead Developer of Runtime Resource Overlay.
The RRO framework provides the possibility to modify the look and feel of an application while it is running, without any need to change or recompile the application source code. At Sony, we use RRO to customise devices according to various operator requirements, since this greatly reduces the number of different software packages we need to build and verify for each product. Runtime Resource Overlay is also one of several enablers of Xperia Themes.
RRO is not only useful for device manufacturers, who can configure how RRO is used, but we hope that it can also be of use for custom ROM developers and other community developers working in the lower levels of Android. However, due to security reasons, app developers currently cannot access the RRO framework.
As RRO extends the Android resource lookup system, the following sections provide an overview of how the system used to work before this addition, before we go into the details of RRO. If you’re already familiar with how resources are handled in Android, and want to skip straight to what’s new, jump down to the section “Runtime Resource Overlay explained”.
What are resources in Android apps?
Resources can be anything from simple booleans, integers and strings, to complex layouts and xml files, or content files such as images and sound. During an application’s lifecycle, the resources will change values dynamically depending on the device’s current orientation, selected language, SIM card, and many other parameters. The current set of these parameters is called the device’s current configuration.
Resources in Android consist of three parts:
- A symbolic name – package.type/name, for example com.android.example.rrotarget.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.
The configuration constraints and values are specified as part of an application’s source code, as outlined in the Providing Resources guide at the Android developers web page. For instance, a resource specified in res/values-sv-land would require the device language to be set to Swedish (sv) and the orientation to be in landscape mode (land) to apply. Resources specified in res/values have no constraints and will be used as a fallback if no other match is found.
From source to package
When an application is compiled, Android’s packaging tool aapt parses the source res/ directory. The input is transformed into resources.arsc, which is a binary blob in the root of the APK containing all information on the application’s resources and assets (except for drawables, xml, and other large files where the actual data is stored in the APK’s res/ directory). resources.arsc is highly optimised for fast lookup speed. During execution, the blob is memory mapped and used as-is.
It is worth noting that not all file names in the res/ directory hierarchy matter. The names of xml files which hold basic types are discarded during compilation. Instead, the resources’ types and names specified in the xml files are kept.
Apart from resources.arsc, aapt is also responsible for generating R.java, a Java class which implements a one-to-one mapping of resources’ symbolic names (string/hello_world and R.string.hello_world) to resource IDs, which are integer values used to speed up resource lookup in runtime.
Illustration of how aapt bundles an application’s source in a package.
Static Resource Overlay explained
Closely related to RRO is Static Resource Overlay (SRO). Like RRO, SRO modifies an application’s resources but unlike its runtime counterpart it does so at compile time.
The aapt tool accepts one or more -S flags, each specifying the path to a resource directory hierarchy. aapt will parse each hierarchy and create a resource.arsc blob based on the union of the hierarchies. In fact, an application’s res directory is just a convention passed to aapt via the first -S flag.
To permanently affect a resource value, build your application using Static Resource Overlay.
How aapt bundles several res hierarchies in a package.
How resource lookup works
An application requests a resource by calling getResources().getType(R.type.name) on the Resources instance associated with it. The request is then processed by the Android framework and a suitable value is returned. As an example, consider an application with a resource drawable/android defined like this:
If a resource lookup is performed when the device is in portrait mode and the current language is set to Swedish, drawable-sv/android.png will be returned, since
- drawable-da is incompatible with the current configuration (language).
- drawable-sv-land is incompatible with the current configuration (orientation).
- drawable is compatible with the current configuration and would have been returned if it had not been for…
- drawable-sv which is compatible with the current configuration and is considered a “better match” than drawable.
What constitutes a better resource match may not be obvious, and you would have to consult the resource lookup code for all the details. As a rule of thumb, a longer list of fulfilled constraints is better than a short one, but different constrains are ranked differently: mnc/mcc, which is the mobile network code and mobile country code, trumps anything, followed by language/country, just to mention a couple of examples.
Note that applications are only responsible for supplying resource IDs. The Android system tracks the current configuration and the set of suitable values. This division of responsibility is key for the resource framework’s dynamic lookup, and for how RRO is able to hook into the resource call-chain.
An illustration of resource lookup. The application sends a resource ID to the system. The system locates the correct package and uses the id and the current configuration to compare each valid resource with each other. The best matching resource is returned to the application.
To show you how this works, let’s look at a sample application called RRO: target which contains a resource with different values for the four configurations listed above. The application will automatically change depending on the system’s current configuration. Unlike in the case when RRO is utilised, the resources in the examples below are all included in the original app.
Example application: Danish, portrait. Note that the app is called RRO:target, but at the moment no overlay is done. How it works when RRO is in use will be shown in the section “Runtime Resource Overlay explained”.
Example application: English, portrait.
Example application: Swedish, landscape.
Example application: Swedish, portrait.
Runtime Resource Overlay explained
Runtime Resource Overlay hooks into the resource lookup framework, shadowing existing values or adding values for new configurations. The resource interface used by the application is unchanged, and the application is therefore not aware that RRO is currently applied, just as an application is currently not aware of its different resource configurations. Therefore, applications can take advantage of RRO without any source code modifications.
Overlay packages contain app resources
A key component of RRO is overlay packages. These are packages which contain alternate versions of one or more of an application’s resources. Any application may have its resources modified by one or more overlay packages. An overlay package only affects a single application, and in this context, the app is called the overlay’s target package.
Rather than specifying pre-existing values for all of the target package’s resources, overlays only provide values for those resource and configuration pairs that are to be changed.
Overlay packages are regular APK files which act like applications. This is because:
- Have an AndroidManifest.xml.
- May be installed.
- Are built using aapt.
However, overlay packages contain no code, and their resources’ symbolic names have to be carefully chosen so as to match (a subset of) those in its target package. A package name, a resource and a description of how it is used is all that is needed to develop an overlay independently of the target application.
Old overlays that are still compatible with new versions of the application can be used without recompilation. There is no compile time support to verify the contents of an overlay package. Such checks have to be deferred until install time when both target and overlay packages are simultaneously available.
When the system loads an application it will automatically also load any associated overlay packages. During lookup, target and overlay packages will all be searched for the best matching resource. Overlays are inspected before the target. If an overlay contains a value compatible with the current configuration, that value is considered a candidate. The best candidate from a package is compared to those of other packages. The net effect is a modified and potentially larger configuration and value pool to search.
Resource lookup with one overlay. The system first looks for a best resource match in the overlay package. The search then continues in the target package. The best resource match may come from either package. A candidate match is discarded only if a new match is strictly better: in case of tiebreaks, the value from the overlay package will be used since it is the first package searched.
An overlay’s target package is referred to using its package name and is specified in the overlay’s manifest. Example of how this is done in the AndroidManifest.xml:
Let’s have a look at our example again, which contains a sample overlay package. It specifies drawable/android for two configurations: the default (drawable) and Swedish (drawable-sv). Installing the samples, the application’s runtime behaviour will have partly changed.
Example application: Danish, portrait. Even though RRO is utilised, the best resource match is found in target package.
Example application: English, portrait. Best resource match found in overlay package.
Example application: Swedish, landscape. Best resource match found in target package.
Example application: Swedish, portrait. Best resource match found in overlay package.
The numerical IDs assigned to resources follow the pattern 0xppttiiii, which consists of the following parts.
- 0xPPttiiii: package (0x01 for system resources, 0x7f for application resources)
- 0xppTTiiii: resource type
- 0xppttIIII: incrementing number
In other words, resource 0xppttiiii is the iiii’th resource of type tt in package pp.
Resource IDs cannot be generated by the build system without full knowledge of all resources in a package, whereas overlay packages can be compiled without access to their target packages. This difference prevents the overlay’s resources from being assigned the same numerical resource IDs as the corresponding resources in its target package. Instead, resource matching is done using the existing user-defined symbolic names.
Obviously, string comparisons would be too costly during resource lookup. To transform from text based to numerical IDs, overlays and their target sync their resources using a mapping between IDs in one package and the IDs for the corresponding resources in the other package. This mapping is created by the new idmap tool during package installation and the data cached in /data/resource-cache. The idmap tool is a part of the RRO framework contribution.
Security in the RRO framework
Since any package can have any resource modified, blindly accepting any overlay package may have severe security consequences. For this reason, only overlays installed in /vendor/overlay, a directory writeable only by the device vendor, are accepted.
A fair relaxation of the current security policy would be to accept downloaded overlays where signatures between target and overlays match, since this would imply the packages were created by the same author. From Sony, we have uploaded patches to Android to support this: Runtime Resource Overlay: support downloaded overlay packages.
Priority of overlays in RRO
In the case of several overlay packages shadowing the same resource, the lookup system needs to know in which order to query the overlays. This is specified using the priority attribute of the overlay tag:
Resource lookup, multiple overlays. The overlays are searched based on their priorities. The target package is always searched last. Candidates for best matches bubble up through the list of packages before a value is returned. In case of a tiebreak, the order of the overlays becomes significant.
The priority attribute can be used to create layers of overlay packages, where one layer would be applied across a family of devices, for example all Xperia devices on a certain hardware platform, another layer would be applied to specific members of that family, and so on.
Possibilities and limitations of RRO
With RRO, it is possible to modify all resource types (integers, strings, drawable, arrays, and so on) for existing or new configurations, and replace or add assets (existing and new ones). It is currently not possible to overlay a package’s AndroidManifest.xml, nor reference resources in the target package from a resource in an overlay package, for example when overlaying xml layouts.
As mentioned in the beginning, Sony uses RRO for customisation and as an enabler for Xperia Themes. Other potential use cases include language translations and development, as well as debugging support. If you want to have a look at the source code of the RRO framework, check out the following changes on the Android review web site: 19337, 46738, 46739 and 46820. What can Runtime Resource Overlay do for you?