androidxで見るMetadataHolderとはなんぞや

# 背景
ちょうど最近ライブラリが更新されたということで、アプリ別言語設定を触っていてAndroidManifestで設定した項目がこちら。

```xml:AndroidManifest.xml
<application>
  <!-- ... -->
  <service
    android:name="androidx.appcompat.app.AppLocalesMetadataHolderService"
    android:enabled="false"
    android:exported="false">
    <meta-data
      android:name="autoStoreLocales"
      android:value="true" />
  </service>
  <!-- ... -->
</application>
```

あるいはandroidx.credentialsでも見た項目はこちら。 (追記: 実際利用する際にこの記述は不要でした)
```xml:AndroidManifest.xml
<application>
  <!-- ... -->
  <service android:name="androidx.credentials.playservices.CredentialProviderMetadataHolder">
    <meta-data
      android:name="androidx.credentials.CREDENTIAL_PROVIDER_KEY"
      android:value="androidx.credentials.playservices.CredentialProviderPlayServicesImpl" />
  </service>
</application>
```

参考: https://qiita.com/verno3632/items/6d8812e3c1f205a0e2a1#androidmanifest


両者とも `MetadataHolder` なるものが使われているが、一体なんぞや？

その謎を解明するため、調査班はAndroid Code Searchの奥地へと向かったーーー

# 結論
ライブラリの挙動をアプリ側で変更したい場合にメタデータの指定先にするServiceです。
ライブラリの挙動をアプリ側で変更するにはコードから変える方法もありますが、アプリケーション単位で変更する場合どこで初期化するかという話になるため、メタデータとして指定するのがシンプルということかと思われます。

## なぜApplicationにメタデータを指定しないのか
applicationに対してmeta-dataを指定することも出来ます。しかしライブラリ側で `applicationにmeta-dataを指定する` という使われ方を選択してしまった場合、そのライブラリを利用するアプリではapplicationにmeta-dataの情報が乗ってしまいます。
端末内の別アプリからアプリのactivityのリストを取得することが出来ますが、それぞれにライブラリのmeta-dataのコピーを含むことになります。
ライブラリ側の一つの <meta-data> が大量の例外とクラッシュを引き落とすことに繋がる可能性があるので、このような使い方を行っていません。

特に今回調査中に発見したように、様々なアプリで広く使われるandroidxでこのように指定すると影響も大きそうです。

参考: https://android.googlesource.com/platform/frameworks/support/+/androidx-main/docs/api_guidelines/resources.md#resources-manifest-metadata

## MetadataHolderというService
`MetadataHolder` という名前がついていますが、そのようなクラスがあるわけではなく単なるServiceです。
このような使い方に対して `MetadataHolder` と名前をつけているようです。
meta-dataを保持するためだけのServiceなので、呼び出されませんし、 `enabled` も `exported` も `false` で宣言するのが正しいです。

# 使用例
いくつかのandroidxのライブラリで使用されています。
## androidx.camera.core
https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:camera/camera-core/src/main/java/androidx/camera/core/impl/MetadataHolderService.java

`CameraXConfig.Provider` を指定します。

## androidx.credentials:credentials-play-services-auth
https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/CredentialProviderMetadataHolder.kt

認証機能(パスワードマネージャー)を設定します。現在使えそうなのはこのライブラリで指定されている `CredentialProviderPlayServicesImpl` くらいのようです。


## androidx.car.app
https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:car/app/app/src/main/java/androidx/car/app/CarAppMetadataHolderService.java

CAR_HARDWARE_MANAGER を指定します。

`androidx.car.app:app-projected` `androidx.car.app:app-automotive` それぞれのライブラリで別のハードウェアマネージャーが用意されています。

## androidx.appcompat
https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:appcompat/appcompat/src/main/java/androidx/appcompat/app/AppLocalesMetadataHolderService.java

アプリ別言語設定をAndroid13未満でどこで管理するか？を表す `autoStoreLocales` を保持します。
androidxのライブラリに任せる(実態はファイル)か、自前でやるかの選択になります。

# 終わりに
`MetadataHolderService` について調査しました。
自前でライブラリを作り、挙動をメタデータで変えたいときに利用方法として整備するのが良いのかも知れません。