Change the value of an app's resources at runtime

A runtime resource overlay (RRO) is a package that changes the resource values of a target package at runtime. For example, an app installed on the system image might change its behavior based upon the value of a resource. Rather than hardcoding the resource value at build time, an RRO installed on a different partition can change the values of the app's resources at runtime.

RROs can be enabled or disabled. You can programmatically set the enable/disable state to toggle an RRO's ability to change resource values. RROs are disabled by default (however, static RROs are enabled by default).

Overlay resources

Overlays work by mapping resources defined in the overlay package to resources defined in the target package. When an app attempts to resolve the value of a resource in the target package, the value of the overlay resource the target resource is mapped to is returned instead.

Set up the manifest

A package is considered an RRO package if it contains an <overlay> tag as a child of the <manifest> tag.

  • The value of the required android:targetPackage attribute specifies the name of the package the RRO intends to overlay.

  • The value of the optional android:targetName attribute specifies the name of the overlayable subset of resources of the target package the RRO intends to overlay. If the target doesn't define an overlayable set of resources, this attribute shouldn't be present.

The following code shows an example overlay AndroidManifest.xml.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.overlay">
    <application android:hasCode="false" />
    <overlay android:targetPackage="com.example.target"
                   android:targetName="OverlayableResources"/>
</manifest>

Overlays can't overlay code, so they can't have DEX files. In addition, the android:hasCode attribute of the <application> tag in the manifest must be set to false.

Define the resources map

In Android 11 or higher, the recommended mechanism for defining the overlay resources map is to create a file in the res/xml directory of the overlay package, enumerate the target resources that should be overlaid and their replacement values, then set the value of the android:resourcesMap attribute of the <overlay> manifest tag to a reference to the resource mapping file.

The following code shows an example res/xml/overlays.xml file.

<?xml version="1.0" encoding="utf-8"?>
<overlay xmlns:android="http://schemas.android.com/apk/res/android" >
    <!-- Overlays string/config1 and string/config2 with the same resource. -->
    <item target="string/config1" value="@string/overlay1" />
    <item target="string/config2" value="@string/overlay1" />

    <!-- Overlays string/config3 with the string "yes". -->
    <item target="string/config3" value="@android:string/yes" />

    <!-- Overlays string/config4 with the string "Hardcoded string". -->
    <item target="string/config4" value="Hardcoded string" />

    <!-- Overlays integer/config5 with the integer "42". -->
    <item target="integer/config5" value="42" />
</overlay>

The following code shows an example overlay manifest.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.overlay">
    <application android:hasCode="false" />
    <overlay android:targetPackage="com.example.target"
                   android:targetName="OverlayableResources"
                   android:resourcesMap="@xml/overlays"/>
</manifest>

Build the package

Android 11 or higher supports a Soong build rule for overlays that prevents Android Asset Packaging Tool 2 (AAPT2) from attempting to dedupe configurations of resources with the same value (--no-resource-deduping) and from removing resources without default configurations (--no-resource-removal). The following code shows an example Android.bp file.

runtime_resource_overlay {
    name: "ExampleOverlay",
    sdk_version: "current",
}

Resolve resources

If a target resource or overlay resource has multiple configurations defined for the resource being queried, the resources runtime returns the value of the configuration that best matches the configuration of the device configuration. To determine which configuration is the best matching configuration, merge the set of the overlay resource configurations into the set of target resource configurations and then follow the regular resource resolution flow (for details, refer to How Android finds the best-matching resource).

For example, if an overlay defines a value for the drawable-en configuration and the target defines a value for drawable-en-port, drawable-en-port has a better match so the value of the target configuration drawable-en-port is chosen at runtime. To overlay all drawable-en configurations, the overlay must define a value for each drawable-en configuration the target defines.

Overlays can reference their own resources, with differing behaviors between Android releases.

  • In Android 11 or higher, each overlay has its own reserved resource ID space that doesn't overlap target resource ID space or other overlay resource ID spaces, so overlays referencing their own resources work as expected.

  • In Android 10 or lower, overlays and target packages share the same resource ID space, which can cause collisions and unexpected behavior when they attempt to reference their own resources using the @type/name syntax.

Enable/disable overlays

Use the OverlayManager API to enable and disable mutable overlays (retrieve the API interface using Context#getSystemService(Context.OVERLAY_SERVICE)). An overlay can be enabled only by the package it targets or by a package with the android.permission.CHANGE_OVERLAY_PACKAGES permission. When an overlay is enabled or disabled, configuration change events propagate to the target package and target activities relaunch.

Restrict overlayable resources

In Android 10 or higher, the <overlayable> XML tag exposes a set of resources that RROs are allowed to overlay. In the following example res/values/overlayable.xml file, string/foo and integer/bar are resources used for theming the device's appearance; to overlay these resources, an overlay must explicitly target the collection of overlayable resources by name.

<!-- The collection of resources for theming the appearance of the device -->
<overlayable name="ThemeResources">
       <policy type="public">
               <item type="string" name="foo/" />
               <item type="integer" name="bar/" />
       </policy>
       ...
</overlayable>

An APK can define multiple <overlayable> tags, but each tag must have a unique name within the package. For example, it is:

  • OK for two different packages to both define <overlayable name="foo">.

  • Not OK for a single APK to have two <overlayable name="foo"> blocks.

The following code shows an example of an overlay in the AndroidManifest.xml file.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
       package="com.my.theme.overlay">
       <application android:hasCode="false" />
       <!-- This overlay will override the ThemeResources resources -->
       <overlay android:targetPackage="android" android:targetName="ThemeResources">
</manifest>

When an app defines an <overlayable> tag, overlays targeting that app:

  • Must specify targetName.

  • Can overlay only the resources listed within the <overlayable> tag.

  • Can target only one <overlayable> name.

You can't enable an overlay targeting a package that exposes overlayable resources but doesn't use android:targetName to target a specific <overlayable> tag.

Restrict policies

Use the <policy> tag to enforce restrictions on overlayable resources. The type attribute specifies which policies an overlay must fulfill to override the included resources. Supported types include the following.

  • public. Any overlay can override the resource.
  • system. Any overlay on the system partition can override the resources.
  • vendor. Any overlay on the vendor partition can override the resources.
  • product. Any overlay on the product partition can override the resources.
  • oem. Any overlay on the oem partition can override the resources.
  • odm. Any overlay on the odm partition can override the resources.
  • signature. Any overlay signed with the same signature as the target APK can override the resources.
  • actor. Any overlay signed with the same signature as the actor APK can override the resources. The actor is declared in named-actor tag in system config.
  • config_signature. Any overlay signed with the same signature as the overlay-config apk can override the resources. The overlay-config is declared in overlay-config-signature tag in system config.

The following code shows an example <policy> tag in the res/values/overlayable.xml file.

<overlayable name="ThemeResources">
   <policy type="vendor" >
       <item type="string" name="foo" />
   </policy>
   <policy type="product|signature"  >
       <item type="string" name="bar" />
       <item type="string" name="baz" />
   </policy>
</overlayable>

To specify multiple policies, use vertical bars (|) as separator characters. When multiple policies are specified, an overlay needs to fulfill only one policy to override the resources listed within the <policy> tag.

Configure overlays

Android supports different mechanisms for configuring the mutability, default state, and priority of overlays depending on the Android release version.

  • Devices running Android 11 or higher can use an OverlayConfig file (config.xml) instead of manifest attributes. Using an overlay file is the recommended method for overlays.

  • All devices can use manifest attributes (android:isStatic and android:priority) to configure static RROs.

Use OverlayConfig

In Android 11 or higher, you can use OverlayConfig to configure the mutability, default state, and priority of overlays. To configure an overlay, create or modify the file located at partition/overlay/config/config.xml, where partition is the partition of the overlay to be configured. To be configured, an overlay must reside in the overlay/ directory of the partition in which the overlay is configured. The following code shows an example product/overlay/config/config.xml.

<config>
    <merge path="OEM-common-rros-config.xml" />
    <overlay package="com.oem.overlay.device" mutable="false" enabled="true" />
    <overlay package="com.oem.green.theme" enabled="true" />
</config>"

The <overlay> tag requires a package attribute that indicates which overlay package is being configured. The optional enabled attribute controls whether or not the overlay is enabled by default (default is false). The optional mutable attribute controls whether or not the overlay is mutable and can have its enabled state changed programmatically at runtime (default is true). Overlays not listed within a configuration file are mutable and disabled by default.

Overlay precedence

When multiple overlays override the same resources, the order of the overlays is important. An overlay has greater precedence than overlays with configurations preceding its own configuration. The precedence order of overlays in different partitions (from least to greatest precedence) is as follows.

  • system
  • vendor
  • odm
  • oem
  • product
  • system_ext

Merge files

Using <merge> tags allows for other configuration files to be merged at the specified position into the configuration file. The path attribute of the tag represents the path of the file to merge relative to the directory containing overlay configuration files.

Use manifest attributes/static RROs

In Android 10 or lower, overlay immutability and precedence are configured using the following manifest attributes.

  • android:isStatic. When the value of this boolean attribute is set to true, the overlay is enabled by default and is immutable, which prevents the overlay from being disabled.

  • android:priority. The value of this numeric attribute (which affects only static overlays) configures the precedence of the overlay when multiple static overlays target the same resource value. A higher number indicates a higher precedence.

The following code shows an example AndroidManifest.xml.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.overlay">
    <application android:hasCode="false" />
    <overlay android:targetPackage="com.example.target"
                   android:isStatic="true"
                   android:priority="5"/>
</manifest>

Changes in Android 11

In Android 11 or higher, if a configuration file is located in partition/overlay/config/config.xml, overlays are configured using that file and android:isStatic and android:priority don't have an effect on overlays located in the partition. Defining an overlay configuration file in any partition enforces the overlay partition precedence.

In addition, Android 11 or higher removes the ability to use static overlays to affect the values of resources read during package installation. For the common use case of using static overlays to change the value of booleans that configure component enabled state, use the <component-override> SystemConfig tag (new in Android 11).

Debug overlays

To manually enable, disable, and dump overlays, use the following overlay manager shell command.

adb shell cmd overlay

OverlayManagerService uses idmap2 to map resource IDs in the target package to resource IDs in the overlay package. The generated ID mappings are stored in /data/resource-cache/. If your overlay isn't working correctly, find the corresponding idmap file for your overlay in /data/resource-cache/, then run the following command.

adb shell idmap2 dump --idmap-path [file]

This command prints the mapping of resources as shown below.

[target res id] - > [overlay res id] [resource name]
0x01040151 -> 0x01050001 string/config_dozeComponent
0x01040152 -> 0x01050002 string/config_dozeDoubleTapSensorType
0x01040153 -> 0x01050003 string/config_dozeLongPressSensorType