ランタイム リソース オーバーレイ(RRO)は、実行時にターゲット パッケージのリソース値を変更するパッケージです。たとえば、システム イメージにインストールされているアプリの動作が、リソースの値に基づいて変わる場合があります。そのような場合、ビルド時にリソース値をハードコードするのではなく、別のパーティションにインストールした RRO によって、実行時にアプリのリソースの値を変更できます。
RRO は有効または無効にできます。有効 / 無効状態をプログラムで設定し、RRO によるリソース値の変更機能を切り替えることができます。RRO はデフォルトでは無効になっています(ただし、静的 RRO はデフォルトで有効になっています)。
リソースをオーバーレイする
オーバーレイは、オーバーレイ パッケージで定義されたリソースを、ターゲット パッケージで定義されたリソースにマッピングすることで機能します。アプリがターゲット パッケージ内のリソースの値を解決しようとすると、代わりに、ターゲット リソースのマッピング先であるオーバーレイ リソースの値が返されます。
マニフェストをセットアップする
<manifest>
タグの子として <overlay>
タグを含むパッケージは、RRO パッケージと見なされます。
必須の
android:targetPackage
属性の値は、RRO によってオーバーレイするパッケージの名前を指定します。オプションの
android:targetName
属性の値は、RRO によってオーバーレイするターゲット パッケージのオーバーレイ可能なリソース サブセットの名前を指定します。ターゲットでオーバーレイ可能なリソースセットが定義されていない場合、この属性は存在しません。
次のコードは、オーバーレイ 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>
オーバーレイは、コードをオーバーレイできないため、DEX ファイルを含めることはできません。また、マニフェストの <application
> タグの android:hasCode
属性を false
に設定する必要があります。
リソースマップを定義する
Android 11 以上でオーバーレイ リソースのマップを定義するには、次のようなメカニズムが推奨されます。オーバーレイ パッケージの res/xml
ディレクトリにファイルを作成し、オーバーレイするターゲット リソースとその置換値を列挙した後、<overlay>
マニフェスト タグの android:resourcesMap
属性の値をリソース マッピング ファイルへの参照に設定するという方法です。
次のコードは、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>
次のコードは、オーバーレイ マニフェストの例を示しています。
<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>
パッケージをビルドする
Android 11 以上は、オーバーレイに対して Soong ビルドルールをサポートしています。このルールによって、Android Asset Packaging Tool 2(AAPT2)が、同じ値を持つリソースの設定の重複排除を試みたり(--no-resource-deduping
)、デフォルト設定のないリソースを削除したりすること(--no-resource-removal
)を防止できます。次のコードは、Android.bp
ファイルの例を示しています。
runtime_resource_overlay {
name: "ExampleOverlay",
sdk_version: "current",
}
リソースを解決する
ターゲット リソースまたはオーバーレイ リソースでクエリ対象のリソースに関する設定が複数定義されている場合、リソース ランタイムは、デバイス設定に最も一致する設定の値を返します。最も一致する設定を判断するには、オーバーレイ リソース設定のセットをターゲット リソース設定のセットに統合した後、通常のリソース解決フローが実施されます(詳細については、Android が最適なリソースを見つける仕組みをご覧ください)。
たとえば、オーバーレイが drawable-en
設定の値を定義し、ターゲットが drawable-en-port
の値を定義している場合、drawable-en-port
のほうがより一致しているので、実行時にはターゲット設定 drawable-en-port
の値が選択されます。すべての drawable-en
設定をオーバーレイするには、ターゲットが定義している各 drawable-en
設定の値をオーバーレイでも定義する必要があります。
オーバーレイは自身のリソースを参照できます。動作は、Android のリリースによって異なります。
Android 11 以上では、各オーバーレイに独自の予約済みリソース ID スペースがあり、ターゲット リソース ID スペースや他のオーバーレイ リソース ID スペースと重複することがないため、自身のリソースを参照するオーバーレイは正常に機能します。
Android 10 以下では、オーバーレイとターゲットのパッケージが同じリソース ID スペースを共有するため、
@type/name
構文を使用してそれぞれが自身のリソースを参照しようとすると、競合や予期せぬ動作が生じる場合があります。
オーバーレイを有効または無効にする
変更可能なオーバーレイを有効または無効にするには OverlayManager
API を使用します(Context#getSystemService(Context.OVERLAY_SERVICE)
を使用して API インターフェースを取得します)。オーバーレイを有効にできるのは、オーバーレイがターゲットとするパッケージ、または android.permission.CHANGE_OVERLAY_PACKAGES
権限を持つパッケージのみです。オーバーレイを有効または無効にすると、設定変更イベントがターゲット パッケージに伝えられ、ターゲット アクティビティが再起動します。
オーバーレイ可能なリソースを制限する
Android 10 以上では、RRO でオーバーレイ可能なリソースのセットを <overlayable>
XML タグで公開します。次の res/values/overlayable.xml
ファイルの例では、string/foo
と integer/bar
は、デバイスの外観のテーマを設定するためのリソースです。これらのリソースをオーバーレイするには、オーバーレイ可能なリソースのコレクションに名前を付けて、オーバーレイのターゲットとして明示的に指定する必要があります。
<!-- 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>
1 つの APK で複数の <overlayable>
タグを定義できますが、各タグの名前はパッケージ内で一意である必要があります。たとえば、次のように定義します。
2 つの異なるパッケージの両方で
<overlayable name="foo">
を定義することは可能です。1 つの APK で 2 つの
<overlayable name="foo">
ブロックを定義することはできません。
次のコードは、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>
アプリで <overlayable>
タグを定義する場合、そのアプリをターゲットにするオーバーレイには次の特徴があります。
targetName
を指定する必要があります。<overlayable>
タグ内にリストされたリソースのみをオーバーレイできます。1 つの
<overlayable>
名のみをターゲットにすることができます。
パッケージ内でオーバーレイ可能なリソースが公開されていても、android:targetName
を使用して特定の <overlayable>
タグがターゲットに指定されていなければ、そのパッケージをターゲットとするオーバーレイは有効にできません。
制限ポリシー
オーバーレイ可能なリソースに制限を適用するには、<policy>
タグを使用します。type
属性では、指定されたリソースをオーバーライドするためにオーバーレイで遵守する必要があるポリシーを指定します。サポートされているタイプは次のとおりです。
public
。任意のオーバーレイでリソースをオーバーライドできます。system
。システム パーティション上の任意のオーバーレイでリソースをオーバーライドできます。vendor
。ベンダー パーティション上の任意のオーバーレイでリソースをオーバーライドできます。product
。プロダクト パーティション上の任意のオーバーレイでリソースをオーバーライドできます。oem
。oem パーティション上の任意のオーバーレイでリソースをオーバーライドできます。odm
。odm パーティション上の任意のオーバーレイでリソースをオーバーライドできます。signature
。ターゲット APK と同じ署名で署名された任意のオーバーレイでリソースをオーバーライドできます。actor
。actor APK と同じ署名で署名された任意のオーバーレイでリソースをオーバーライドできます。actor はシステム構成の named-actor タグで宣言されます。config_signature
。overlay-config APK と同じ署名で署名された任意のオーバーレイでリソースをオーバーライドできます。overlay-config はシステム構成の overlay-config-signature タグで宣言されます。
次のコードは、res/values/overlayable.xml
ファイルの <policy>
タグの例を示しています。
<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>
複数のポリシーを指定するには、区切り文字として縦棒(|)を使用します。複数のポリシーを指定した場合、<policy>
タグ内にリストされたリソースをオーバーライドするために遵守する必要があるポリシーは 1 つだけです。
オーバーレイを設定する
Android は、Android のリリース バージョンに応じてオーバーレイの可変性、デフォルト状態、優先度を設定するさまざまなメカニズムをサポートしています。
Android 11 以降を搭載したデバイスでは、マニフェスト属性の代わりに
OverlayConfig
ファイル(config.xml
)を使用できます。オーバーレイにはオーバーレイ ファイルの使用をおすすめします。すべてのデバイスで、静的 RRO の設定にマニフェスト属性(
android:isStatic
とandroid:priority
)を使用できます。
OverlayConfig を使用する
Android 11 以上では、OverlayConfig
を使用してオーバーレイの可変性、デフォルト状態、優先度を設定できます。オーバーレイを設定するには、partition/overlay/config/config.xml
でオーバーレイ ファイルを作成するか、同じ場所のオーバーレイ ファイルを変更します。この場合、partition
は、設定対象オーバーレイのパーティションです。設定するには、オーバーレイが設定されているパーティションの overlay/
ディレクトリにオーバーレイが存在している必要があります。次のコードは、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>"
<overlay>
タグには、設定対象のオーバーレイ パッケージを示す package
属性が必要です。オプションの enabled
属性は、オーバーレイをデフォルトで有効にするかどうかを制御します(デフォルトは false
)。オプションの mutable
属性は、オーバーレイを変更可能にするかどうか、および実行時に有効化状態をプログラムで変更できるかどうかを制御します(デフォルトは true
)。構成ファイル内にリストされていないオーバーレイは変更可能であり、デフォルトで無効になっています。
オーバーレイの優先順位
複数のオーバーレイが同じリソースをオーバーライドしている場合は、オーバーレイの順序が重要になります。上位の設定を持つオーバーレイほど優先順位が低くなります。異なるパーティションにあるオーバーレイの優先順位(低いものから順に)は、次のとおりです。
system
vendor
odm
oem
product
system_ext
ファイルを統合する
<merge>
タグを使用すると、構成ファイル内の指定の場所に他の構成ファイルを統合できます。このタグの path
属性は、統合するファイルのパス(オーバーレイ構成ファイルが含まれるディレクトリを基準とする相対パス)を表します。
マニフェスト属性 / 静的 RRO を使用する
Android 10 以下でオーバーレイの不変性と優先順位を設定するには、以下のマニフェスト属性を使用します。
android:isStatic
。このブール値属性の値がtrue
に設定されている場合、オーバーレイはデフォルトで有効とされ、変更できません。これにより、オーバーレイは無効化できなくなります。android:priority
。この数値属性の値(静的なオーバーレイにのみ影響します)は、複数の静的オーバーレイが同じリソース値をターゲットにしている場合のオーバーレイの優先順位を設定します。数値が大きいほど優先度が高くなります。
次のコードは、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>
Android 11 の変更点
Android 11 以降では、構成ファイルが partition/overlay/config/config.xml
にある場合、そのファイルを使用してオーバーレイが設定されます。android:isStatic
と android:priority
はパーティション内のオーバーレイに影響しません。任意のパーティションでオーバーレイ構成ファイルを定義すると、オーバーレイ パーティションの優先順位が適用されます。
さらに、Android 11 以降では、パッケージのインストール時に読み取られるリソースの値に静的オーバーレイで影響を及ぼす機能が削除されています。一般的なユースケースとしては、コンポーネントの有効化状態を設定するブール値の値を静的オーバーレイで変更する場合、<component-override>
SystemConfig
タグを使用します(Android 11 の新機能)。
オーバーレイをデバッグする
オーバーレイの有効化、無効化、ダンプを手動で行うには、オーバーレイ マネージャーの次のシェルコマンドを使用します。
adb shell cmd overlay
OverlayManagerService
は idmap2
を使用して、ターゲット パッケージのリソース ID をオーバーレイ パッケージのリソース ID にマッピングします。生成された ID のマッピングは /data/resource-cache/
に格納されます。オーバーレイが正常に機能しない場合は、/data/resource-cache/
でオーバーレイの対応する idmap
ファイルを探して、次のコマンドを実行します。
adb shell idmap2 dump --idmap-path [file]
このコマンドは、次のようなリソースのマッピングを出力します。
[target res id] - > [overlay res id] [resource name]
0x01040151 -> 0x01050001 string/config_dozeComponent
0x01040152 -> 0x01050002 string/config_dozeDoubleTapSensorType
0x01040153 -> 0x01050003 string/config_dozeLongPressSensorType