Une couche de ressources d'exécution (RRO) est un package qui modifie les valeurs de ressources d'un package cible au moment de l'exécution. Par exemple, une application installée sur l'image système peut modifier son comportement en fonction de la valeur d'une ressource. Plutôt que d'encoder en dur la valeur de la ressource au moment de la compilation, un RRO installé sur une autre partition peut modifier les valeurs des ressources de l'application au moment de l'exécution.
Les RRO peuvent être activés ou désactivés. Vous pouvez définir l'état d'activation/de désactivation de manière programmatique pour activer ou désactiver la capacité d'un RRO à modifier les valeurs de ressources. Les RRO sont désactivées par défaut (toutefois, les RRO statiques sont activées par défaut).
Superposer des ressources
Les calques fonctionnent en mappant les ressources définies dans le package de calque aux ressources définies dans le package cible. Lorsqu'une application tente de résoudre la valeur d'une ressource dans le package cible, la valeur de la ressource de superposition à laquelle la ressource cible est mappée est renvoyée à la place.
Configurer le fichier manifeste
Un package est considéré comme un package RRO s'il contient une balise <overlay>
en tant qu'enfant de la balise <manifest>
.
La valeur de l'attribut
android:targetPackage
obligatoire spécifie le nom du package que l'ORR prévoit de superposer.La valeur de l'attribut facultatif
android:targetName
spécifie le nom du sous-ensemble superposable de ressources du package cible que l'ORR a l'intention de superposer. Si la cible ne définit pas d'ensemble de ressources superposables, cet attribut ne doit pas être présent.
Le code suivant montre un exemple de superposition 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>
Les superpositions ne peuvent pas se superposer au code. Elles ne peuvent donc pas avoir de fichiers DEX. De plus, l'attribut android:hasCode
de la balise <application
> dans le fichier manifeste doit être défini sur false
.
Définir le mappage des ressources
Dans Android 11 ou version ultérieure, le mécanisme recommandé pour définir la carte des ressources de superposition consiste à créer un fichier dans le répertoire res/xml
du package de superposition, à énumérer les ressources cibles qui doivent être superposées et leurs valeurs de remplacement, puis à définir la valeur de l'attribut android:resourcesMap
de la balise de fichier manifeste <overlay>
sur une référence au fichier de mappage des ressources.
Le code suivant illustre un exemple de fichier res/xml/overlays.xml
.
<?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>
Le code suivant illustre un exemple de fichier manifeste de superposition.
<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>
Créer le package
Android 11 ou version ultérieure est compatible avec une règle de compilation Soong pour les superpositions qui empêche Android Asset Packaging Tool 2 (AAPT2) de tenter de dédupliquer les configurations de ressources ayant la même valeur (--no-resource-deduping
) et de supprimer les ressources sans configurations par défaut (--no-resource-removal
). Le code suivant montre un exemple de fichier Android.bp
.
runtime_resource_overlay {
name: "ExampleOverlay",
sdk_version: "current",
}
Résoudre les ressources
Si une ressource cible ou de superposition comporte plusieurs configurations définies pour la ressource interrogée, le runtime des ressources renvoie la valeur de la configuration qui correspond le mieux à la configuration de l'appareil. Pour déterminer quelle configuration est la plus adaptée, fusionnez l'ensemble des configurations de ressources de superposition dans l'ensemble des configurations de ressources cibles, puis suivez le flux de résolution de ressources habituel (pour en savoir plus, consultez Comment Android détermine-t-il la ressource la plus pertinente ?).
Par exemple, si une superposition définit une valeur pour la configuration drawable-en
et que la cible définit une valeur pour drawable-en-port
, drawable-en-port
correspond mieux. La valeur de la configuration cible drawable-en-port
est donc choisie lors de l'exécution. Pour superposer toutes les configurations drawable-en
, la superposition doit définir une valeur pour chaque configuration drawable-en
définie par la cible.
Les couches peuvent référencer leurs propres ressources, avec des comportements différents selon les versions d'Android.
Dans Android 11 ou version ultérieure, chaque superposition possède son propre espace d'ID de ressource réservé qui ne chevauche pas l'espace d'ID de ressource cible ni les autres espaces d'ID de ressource de superposition. Les superpositions référençant leurs propres ressources fonctionnent donc comme prévu.
Dans Android 10 ou version antérieure, les packages de superposition et cibles partagent le même espace d'ID de ressource, ce qui peut entraîner des conflits et un comportement inattendu lorsqu'ils tentent de référencer leurs propres ressources à l'aide de la syntaxe
@type/name
.
Activer/Désactiver les calques
Les calques peuvent être activés ou désactivés manuellement ou de manière programmatique.
Désactiver ou activer manuellement les calques
Pour activer et valider manuellement un RRO, exécutez la commande suivante :
adb shell cmd overlay enable --user current com.example.carrro
adb shell cmd overlay list --user current | grep -i com.example com.example.carrro
Cela active le RRO pour l'utilisateur système (userId = 0
) qui possède SystemUI.
Cette instruction n'a aucune incidence sur les applications démarrées par l'utilisateur au premier plan (userId = 10
). Pour activer l'RRO pour l'utilisateur au premier plan, utilisez le paramètre -–user 10
:
adb shell cmd overlay enable --user 10 com.example.carrro
Activer ou désactiver les calques de manière programmatique
Utilisez l'API OverlayManager
pour activer et désactiver les calques modifiables (récupérez l'interface de l'API à l'aide de Context#getSystemService(Context.OVERLAY_SERVICE)
). Un calque ne peut être activé que par le package qu'il cible ou par un package disposant de l'autorisation android.permission.CHANGE_OVERLAY_PACKAGES
. Lorsqu'une superposition est activée ou désactivée, les événements de changement de configuration se propagent au package cible et les activités cibles sont relancées.
Restreindre les ressources superposables
Dans Android 10 ou version ultérieure, la balise XML <overlayable>
expose un ensemble de ressources que les RRO sont autorisés à superposer. Dans l'exemple de fichier res/values/overlayable.xml
suivant, string/foo
et integer/bar
sont des ressources utilisées pour personnaliser l'apparence de l'appareil. Pour superposer ces ressources, une superposition doit cibler explicitement la collection de ressources superposables par nom.
<!-- 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>
Un APK peut définir plusieurs balises <overlayable>
, mais chaque balise doit avoir un nom unique dans le package. Par exemple :
Il est possible que deux packages différents définissent
<overlayable name="foo">
.Il n'est pas autorisé qu'un même fichier APK contienne deux blocs
<overlayable name="foo">
.
Le code suivant montre un exemple de superposition dans le fichier AndroidManifest.xml
.
<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>
Lorsqu'une application définit un tag <overlayable>
, les overlays ciblant cette application :
Vous devez spécifier
targetName
.Ne peut superposer que les ressources listées dans la balise
<overlayable>
.Ne peut cibler qu'un seul nom
<overlayable>
.
Vous ne pouvez pas activer de superposition ciblant un package qui expose des ressources superposables, mais qui n'utilise pas android:targetName
pour cibler une balise <overlayable>
spécifique.
Restreindre les règles
Utilisez le tag <policy>
pour appliquer des restrictions aux ressources superposables. L'attribut type
spécifie les règles qu'une superposition doit respecter pour remplacer les ressources incluses. Voici les types acceptés :
public
. N'importe quelle superposition peut remplacer la ressource.system
. Toute superposition sur la partition système peut remplacer les ressources.vendor
. Toute superposition sur la partition du fournisseur peut remplacer les ressources.product
. Toute superposition sur la partition de produits peut remplacer les ressources.oem
. Toute superposition sur la partition OEM peut remplacer les ressources.odm
. Toute superposition sur la partition odm peut remplacer les ressources.signature
. Toute superposition signée avec la même signature que l'APK cible peut remplacer les ressources.actor
. Toute superposition signée avec la même signature que l'APK de l'acteur peut remplacer les ressources. L'acteur est déclaré dans la balise named-actor de la configuration système.config_signature
. Toute superposition signée avec la même signature que l'APK overlay-config peut remplacer les ressources. La configuration de superposition est déclarée dans la balise overlay-config-signature de la configuration système.
Le code suivant montre un exemple de balise <policy>
dans le fichier res/values/overlayable.xml
.
<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>
Pour spécifier plusieurs règles, utilisez des barres verticales (|) comme séparateurs.
Lorsque plusieurs règles sont spécifiées, une superposition n'a besoin de respecter qu'une seule règle pour remplacer les ressources listées dans la balise <policy>
.
Configurer les superpositions
Android est compatible avec différents mécanismes de configuration de la mutabilité, de l'état par défaut et de la priorité des superpositions, en fonction de la version d'Android.
Les appareils fonctionnant sous Android 11 ou version ultérieure peuvent utiliser un fichier
OverlayConfig
(config.xml
) au lieu des attributs du fichier manifeste. L'utilisation d'un fichier de superposition est la méthode recommandée pour les superpositions.Tous les appareils peuvent utiliser les attributs de fichier manifeste (
android:isStatic
etandroid:priority
) pour configurer les RRO statiques.
Utiliser OverlayConfig
Dans Android 11 ou version ultérieure, vous pouvez utiliser OverlayConfig
pour configurer la mutabilité, l'état par défaut et la priorité des calques. Pour configurer une superposition, créez ou modifiez le fichier situé à l'adresse partition/overlay/config/config.xml
, où partition
correspond à la partition de la superposition à configurer. Pour être configurée, une superposition doit résider dans le répertoire overlay/
de la partition dans laquelle elle est configurée. Le code suivant illustre un exemple de fichier 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>"
La balise <overlay>
nécessite un attribut package
qui indique le package d'overlay en cours de configuration. L'attribut facultatif enabled
contrôle si la superposition est activée par défaut (la valeur par défaut est false
). L'attribut facultatif mutable
contrôle si la superposition est mutable et si son état activé peut être modifié de manière programmatique au moment de l'exécution (la valeur par défaut est true
). Les superpositions qui ne sont pas listées dans un fichier de configuration sont mutables et désactivées par défaut.
Priorité des superpositions
Lorsque plusieurs superpositions remplacent les mêmes ressources, l'ordre des superpositions est important. Une superposition a une priorité plus élevée que les superpositions dont les configurations précèdent la sienne. L'ordre de priorité des superpositions dans différentes partitions (de la priorité la plus faible à la priorité la plus élevée) est le suivant :
system
vendor
odm
oem
product
system_ext
Fusionner des fichiers
L'utilisation de balises <merge>
permet de fusionner d'autres fichiers de configuration à l'emplacement spécifié dans le fichier de configuration. L'attribut path
de la balise représente le chemin d'accès du fichier à fusionner par rapport au répertoire contenant les fichiers de configuration de superposition.
Utiliser des attributs de fichier manifeste/des RRO statiques
Dans Android 10 ou une version antérieure, l'immuabilité et la priorité des couches sont configurées à l'aide des attributs de fichier manifeste suivants.
android:isStatic
. Lorsque la valeur de cet attribut booléen est définie surtrue
, la superposition est activée par défaut et est immuable, ce qui empêche sa désactivation.android:priority
. La valeur de cet attribut numérique (qui n'affecte que les calques statiques) configure la priorité du calque lorsque plusieurs calques statiques ciblent la même valeur de ressource. Plus le nombre est élevé, plus la priorité est élevée.
Le code suivant illustre un exemple de fichier 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>
Modifications apportées à Android 11
Dans Android 11 ou version ultérieure, si un fichier de configuration se trouve dans partition/overlay/config/config.xml
, les superpositions sont configurées à l'aide de ce fichier, et android:isStatic
et android:priority
n'ont aucun effet sur les superpositions situées dans la partition. La définition d'un fichier de configuration de superposition dans une partition quelconque applique la priorité de la partition de superposition.
De plus, Android 11 ou version ultérieure supprime la possibilité d'utiliser des calques statiques pour modifier les valeurs des ressources lues lors de l'installation du package. Pour le cas d'utilisation courant des calques statiques permettant de modifier la valeur des booléens qui configurent l'état activé des composants, utilisez la balise <component-override>
SystemConfig
(nouveauté d'Android 11).
Calques de débogage
Pour activer, désactiver et vider manuellement les calques, utilisez la commande shell du gestionnaire de calques suivante.
adb shell cmd overlay
L'utilisation de enable
sans spécifier d'utilisateur affecte l'utilisateur actuel, c'est-à-dire l'utilisateur système (userId = 0
) qui possède l'interface utilisateur système. Cela n'a pas d'incidence sur l'utilisateur au premier plan (userId = 10
), qui est propriétaire des applications. Pour activer le RRO pour l'utilisateur au premier plan, utilisez le paramètre –-user 10
:
adb shell cmd overlay enable --user 10 com.example.carrro
OverlayManagerService
utilise idmap2
pour mapper les ID de ressources du package cible sur les ID de ressources du package de superposition. Les mappages d'ID générés sont stockés dans /data/resource-cache/
. Si votre superposition ne fonctionne pas correctement, recherchez le fichier idmap
correspondant dans /data/resource-cache/
, puis exécutez la commande suivante.
adb shell idmap2 dump --idmap-path [file]
Cette commande affiche le mappage des ressources, comme indiqué ci-dessous.
[target res id] - > [overlay res id] [resource name]
0x01040151 -> 0x01050001 string/config_dozeComponent
0x01040152 -> 0x01050002 string/config_dozeDoubleTapSensorType
0x01040153 -> 0x01050003 string/config_dozeLongPressSensorType