Laufzeitressourcen-Overlays (RROs)

Ein Runtime Resource Overlay (RRO) ist ein Paket, das die Ressourcenwerte eines Zielpakets zur Laufzeit ändert. Beispielsweise kann eine auf dem Systemabbild installierte App ihr Verhalten basierend auf dem Wert einer Ressource ändern. Anstatt den Ressourcenwert zur Erstellungszeit fest zu codieren, kann ein auf einer anderen Partition installiertes RRO die Werte der App-Ressourcen zur Laufzeit ändern.

RROs können aktiviert oder deaktiviert werden. Sie können den Aktivierungs-/Deaktivierungsstatus programmgesteuert festlegen, um die Fähigkeit eines RRO zum Ändern von Ressourcenwerten umzuschalten. RROs sind standardmäßig deaktiviert ( statische RROs sind jedoch standardmäßig aktiviert).

Ressourcen überlagern

Überlagerungen funktionieren, indem sie im Überlagerungspaket definierte Ressourcen Ressourcen zuordnen, die im Zielpaket definiert sind. Wenn eine App versucht, den Wert einer Ressource im Zielpaket aufzulösen, wird stattdessen der Wert der Overlay-Ressource zurückgegeben, der die Zielressource zugeordnet ist.

Einrichten des Manifests

Ein Paket wird als RRO-Paket betrachtet, wenn es ein <overlay> -Tag als untergeordnetes Element des <manifest> -Tags enthält.

  • Der Wert des erforderlichen android:targetPackage Attributs gibt den Namen des Pakets an, das das RRO überlagern möchte.

  • Der Wert des optionalen android:targetName Attributs gibt den Namen der überlagerbaren Teilmenge von Ressourcen des Zielpakets an, die das RRO überlagern möchte. Wenn das Ziel keinen überlagerbaren Satz von Ressourcen definiert, sollte dieses Attribut nicht vorhanden sein.

Der folgende Code zeigt ein Beispiel-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 können keinen Code überlagern, also können sie keine DEX-Dateien enthalten. Außerdem muss das Attribut android:hasCode des Tags <application > im Manifest auf false gesetzt werden.

Definieren der Ressourcenkarte

In Android 11 oder höher besteht der empfohlene Mechanismus zum Definieren der Overlay-Ressourcenzuordnung darin, eine Datei im res/xml -Verzeichnis des Overlay-Pakets zu erstellen, die zu überlagernden Zielressourcen und ihre Ersatzwerte aufzuzählen und dann den Wert von festzulegen android:resourcesMap -Attribut des Manifest-Tags <overlay> zu einem Verweis auf die Ressourcenzuordnungsdatei.

Der folgende Code zeigt eine Beispieldatei 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>

Der folgende Code zeigt ein Beispiel für ein 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>

Aufbau des Pakets

Android 11 oder höher unterstützt eine Soong-Build-Regel für Overlays, die verhindert, dass Android Asset Packaging Tool 2 (AAPT2) versucht, Konfigurationen von Ressourcen mit demselben Wert ( --no-resource-deduping ) zu deduplizieren und Ressourcen ohne Standardkonfigurationen ( --no-resource-removal ). Der folgende Code zeigt eine Android.bp -Beispieldatei.

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

Ressourcen auflösen

Wenn für eine Zielressource oder Overlay-Ressource mehrere Konfigurationen für die abgefragte Ressource definiert sind, gibt die Ressourcenlaufzeit den Wert der Konfiguration zurück, die der Konfiguration der Gerätekonfiguration am besten entspricht. Um zu bestimmen, welche Konfiguration die am besten passende Konfiguration ist, führen Sie den Satz der Overlay-Ressourcenkonfigurationen mit dem Satz der Zielressourcenkonfigurationen zusammen und folgen Sie dann dem regulären Ablauf der Ressourcenauflösung (Einzelheiten finden Sie unter Wie Android die am besten passende Ressource findet ).

Wenn beispielsweise ein Overlay einen Wert für die drawable-en Konfiguration definiert und das Ziel einen Wert für drawable-en-port definiert, hat drawable-en-port eine bessere Übereinstimmung, sodass der Wert der Zielkonfiguration drawable-en-port ist zur Laufzeit gewählt. Um alle drawable-en Konfigurationen zu überlagern, muss das Overlay einen Wert für jede drawable-en Konfiguration definieren, die das Ziel definiert.

Overlays können auf ihre eigenen Ressourcen verweisen, wobei sich das Verhalten zwischen den Android-Releases unterscheidet.

  • In Android 11 oder höher hat jedes Overlay seinen eigenen reservierten Ressourcen-ID-Bereich, der sich nicht mit dem Ziel-Ressourcen-ID-Bereich oder anderen Overlay-Ressourcen-ID-Bereichen überschneidet, sodass Overlays, die auf ihre eigenen Ressourcen verweisen, wie erwartet funktionieren.

  • In Android 10 oder niedriger teilen sich Overlays und Zielpakete denselben Ressourcen-ID-Bereich, was zu Kollisionen und unerwartetem Verhalten führen kann, wenn sie versuchen, ihre eigenen Ressourcen mit der @type/name Syntax zu referenzieren.

Overlays aktivieren/deaktivieren

Verwenden Sie die OverlayManager API, um änderbare Overlays zu aktivieren und zu deaktivieren (rufen Sie die API-Schnittstelle mit Context#getSystemService(Context.OVERLAY_SERVICE) ). Ein Overlay kann nur durch das Paket, auf das es abzielt, oder durch ein Paket mit der android.permission.CHANGE_OVERLAY_PACKAGES . Wenn ein Overlay aktiviert oder deaktiviert wird, werden Konfigurationsänderungsereignisse an das Zielpaket weitergegeben und Zielaktivitäten werden neu gestartet.

Einschränken überlagerbarer Ressourcen

In Android 10 oder höher stellt das XML-Tag <overlayable> eine Reihe von Ressourcen bereit, die RROs überlagern dürfen. In der folgenden Beispieldatei res/values/overlayable.xml sind string/foo und integer/bar Ressourcen, die zum Thematisieren des Erscheinungsbilds des Geräts verwendet werden; Um diese Ressourcen zu überlagern, muss eine Überlagerung explizit die Sammlung von überlagerbaren Ressourcen nach Namen anvisieren.

<!-- 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>

Ein APK kann mehrere <overlayable> -Tags definieren, aber jedes Tag muss innerhalb des Pakets einen eindeutigen Namen haben. Zum Beispiel ist es:

  • OK für zwei verschiedene Pakete, die beide <overlayable name="foo"> definieren.

  • Nicht in Ordnung, wenn ein einzelnes APK zwei <overlayable name="foo"> Blöcke hat.

Der folgende Code zeigt ein Beispiel für eine Überlagerung in der Datei 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>

Wenn eine App ein <overlayable> -Tag definiert, werden Overlays, die auf diese App abzielen:

  • targetName muss angegeben werden.

  • Kann nur die im Tag <overlayable> aufgeführten Ressourcen überlagern.

  • Kann nur auf einen <overlayable> .

Sie können kein Overlay aktivieren, das auf ein Paket abzielt, das überlagerbare Ressourcen verfügbar macht, aber android:targetName nicht verwendet, um auf ein bestimmtes <overlayable> -Tag abzuzielen.

Einschränkende Richtlinien

Verwenden Sie das <policy> -Tag, um Einschränkungen für überlagerbare Ressourcen zu erzwingen. Das type Attribut gibt an, welche Richtlinien ein Overlay erfüllen muss, um die enthaltenen Ressourcen zu überschreiben. Zu den unterstützten Typen gehören die folgenden.

  • public . Jede Überlagerung kann die Ressource überschreiben.
  • system . Jede Überlagerung auf der Systempartition kann die Ressourcen überschreiben.
  • vendor . Jede Überlagerung auf der Anbieterpartition kann die Ressourcen überschreiben.
  • product . Jede Überlagerung auf der Produktpartition kann die Ressourcen überschreiben.
  • signature . Jedes Overlay, das mit derselben Signatur wie das Ziel-APK signiert ist, kann die Ressourcen überschreiben.

Der folgende Code zeigt ein Beispiel für ein <policy> -Tag in der Datei 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>

Um mehrere Richtlinien anzugeben, verwenden Sie vertikale Striche (|) als Trennzeichen. Wenn mehrere Richtlinien angegeben sind, muss ein Overlay nur eine Richtlinie erfüllen, um die im <policy> -Tag aufgelisteten Ressourcen zu überschreiben.

Overlays konfigurieren

Android unterstützt je nach Android-Release-Version unterschiedliche Mechanismen zum Konfigurieren der Veränderlichkeit, des Standardzustands und der Priorität von Overlays.

  • Geräte mit Android 11 oder höher können anstelle von Manifestattributen eine OverlayConfig -Datei ( config.xml ) verwenden. Die Verwendung einer Overlay-Datei ist die empfohlene Methode für Overlays.

  • Alle Geräte können Manifestattribute ( android:isStatic und android:priority ) verwenden, um statische RROs zu konfigurieren.

Verwenden von OverlayConfig

In Android 11 oder höher können Sie OverlayConfig verwenden, um die Veränderbarkeit, den Standardstatus und die Priorität von Overlays zu konfigurieren. Um ein Overlay zu konfigurieren, erstellen oder ändern Sie die Datei unter partition/overlay/config/config.xml , wobei partition die Partition des zu konfigurierenden Overlays ist. Um konfiguriert zu werden, muss sich ein Overlay im Verzeichnis overlay/ der Partition befinden, in der das Overlay konfiguriert ist. Der folgende Code zeigt ein Beispiel 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>"

Das Tag <overlay> erfordert ein package , das angibt, welches Overlay-Paket konfiguriert wird. Das optionale Attribut enabled steuert, ob das Overlay standardmäßig aktiviert ist oder nicht (Standard ist false ). Das optionale Attribut mutable steuert, ob das Overlay änderbar ist oder nicht, und kann seinen aktivierten Zustand zur Laufzeit programmgesteuert ändern (Standard ist true ). Überlagerungen, die nicht in einer Konfigurationsdatei aufgeführt sind, sind veränderbar und standardmäßig deaktiviert.

Overlay-Vorrang

Wenn mehrere Overlays dieselben Ressourcen überschreiben, ist die Reihenfolge der Overlays wichtig. Eine Überlagerung hat einen höheren Vorrang als Überlagerungen mit Konfigurationen, die ihrer eigenen Konfiguration vorausgehen. Die Prioritätsreihenfolge von Overlays in verschiedenen Partitionen (von der geringsten zur größten Priorität) ist wie folgt.

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

Dateien zusammenführen

Die Verwendung von <merge> -Tags ermöglicht es, andere Konfigurationsdateien an der angegebenen Position in die Konfigurationsdatei einzufügen. Das path des Tags stellt den Pfad der zusammenzuführenden Datei relativ zum Verzeichnis dar, das die Overlay-Konfigurationsdateien enthält.

Verwenden von Manifestattributen (statische RROs)

In Android 10 oder niedriger werden Overlay-Unveränderlichkeit und -Vorrang mithilfe der folgenden Manifestattribute konfiguriert.

  • android:isStatic . Wenn der Wert dieses booleschen Attributs auf true gesetzt ist, ist das Overlay standardmäßig aktiviert und unveränderlich, wodurch verhindert wird, dass das Overlay deaktiviert wird.

  • android:priority . Der Wert dieses numerischen Attributs (das sich nur auf statische Überlagerungen auswirkt) konfiguriert die Priorität der Überlagerung, wenn mehrere statische Überlagerungen auf denselben Ressourcenwert abzielen. Eine höhere Zahl zeigt eine höhere Priorität an.

Der folgende Code zeigt ein Beispiel 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>

Änderungen in Android 11

Wenn sich in Android 11 oder höher eine Konfigurationsdatei in partition/overlay/config/config.xml , werden Overlays mithilfe dieser Datei konfiguriert, und android:isStatic und android:priority haben keine Auswirkung auf Overlays in der Partition. Das Definieren einer Overlay-Konfigurationsdatei in einer beliebigen Partition erzwingt den Vorrang der Overlay-Partition.

Darüber hinaus entfernt Android 11 oder höher die Möglichkeit, statische Overlays zu verwenden, um die Werte von Ressourcen zu beeinflussen, die während der Paketinstallation gelesen werden. Verwenden Sie für den allgemeinen Anwendungsfall der Verwendung statischer Overlays zum Ändern des Werts von booleschen Werten, die den Status der aktivierten Komponente konfigurieren, das SystemConfig -Tag <component-override> (neu in Android 11).

Debuggen von Überlagerungen

Um Overlays manuell zu aktivieren, zu deaktivieren und auszugeben, verwenden Sie den folgenden Overlay-Manager-Shell-Befehl.

adb shell cmd overlay

OverlayManagerService verwendet idmap2 , um Ressourcen-IDs im Zielpaket Ressourcen-IDs im Overlay-Paket zuzuordnen. Die generierten ID-Zuordnungen werden in /data/resource-cache/ gespeichert. Wenn Ihr Overlay nicht richtig funktioniert, suchen Sie die entsprechende idmap -Datei für Ihr Overlay in /data/resource-cache/ und führen Sie dann den folgenden Befehl aus.

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

Dieser Befehl druckt die Ressourcenzuordnung wie unten gezeigt.

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