このページでは、システム ユーザーにとって不要なパッケージを特定して削除することで、パフォーマンスを改善する方法について説明します。
不要なパッケージを無効にする
Automotive では、システム ユーザーはヘッドレスです。つまり、システム ユーザーは、人間が使用したり、直接アクセスすることを意図したものではありません。そのため、多くのアプリやサービスはシステム ユーザーで実行する必要はなく、無効にすることでパフォーマンスを改善できます。そのため、システム ユーザー(ユーザー 0)にとって不要なアプリを削除するオプションが用意されています。
このページでは、次の 2 種類のユーザーについて説明します。
- SYSTEM。常にユーザー 0
- FULL。人間による使用が想定されているユーザー(システム ユーザー以外のユーザー)、ユーザー 10 以上
Android 11
Android 11 では、config_userTypePackageWhitelistMode
構成を変更します。フラグは組み合わせることができます。この場合、5
は 1
と 4
(フラグ 1
と 4
の組み合わせ)に相当します。
フラグ | 説明 |
---|---|
0 |
許可リストを無効にします。すべてのシステム パッケージをインストールします(記録はされません)。 |
1 |
適用します。許可リストに登録されているシステム パッケージのみインストールします。 |
2 |
許可リストに登録されていないパッケージを記録します。 |
4 |
許可リストファイルに記載されていないパッケージを、すべてのユーザーを対象とした許可リストに暗黙的に登録します。 |
8 |
4 と同じです(システム ユーザーが対象)。 |
16 |
OTA を無視します。OTA 中はシステム パッケージをインストールしません。 |
次の一般的なシナリオを検討してください。
- 完全な許可リストで機能を有効にする:
1
(完全に適用) - 不完全な許可リストで機能を有効にする:
5
SYSTEM
ユーザーがローカルでの開発をスムーズに行えるよう機能を有効にする:9
(暗黙的な許可リスト)- 今後有効になることがないように機能を無効にする:
16
- 機能を無効にして、以前の効果を元に戻す:
0
デバイスの sysconfig
ディレクトリに XML ファイルをインストールします(これはデバイスのシステム イメージのビルドに使用する makefile(.mk
)が含まれているのと同じディレクトリです)。XML ファイルに名前を付ける場合は、ビルドでパッケージが定義されている場所を含めます(例: preinstalled-packages-product-car-CAR_PRODUCT_NAME.xml
)。
<!- this package will be installed for both FULL and SYSTEM user --> <install-in-user-type package="com.android.bluetooth"-> <install-in user-type="FULL" /-> <install-in user-type="SYSTEM" /-> </install-in-user-type-> <!- this package will only be installed for both FULL user --> <install-in-user-type package="com.android.car.calendar"-> <install-in user-type="FULL" > </install-in-user-type->
Android 9 および Android 10
Android 9 と Android 10 でこの機能を設定するには、以下を行います。
frameworks/base/core/res/res/values/config.xml
からconfig_systemUserPackagesBlacklistSupported
構成をオーバーレイし、true
に設定します。この機能を有効にすると、デフォルトでは、システム ユーザーと FULL ユーザーの両方にすべてのパッケージがインストールされます。- システム ユーザーに対して無効にする必要があるパッケージをリストする
config.xml
ファイルを作成します。次に例を示します。<config> <!-- This package will be uninstalled for the system user --> <system-user-blacklisted-app package="com.google.car.calendar" /> </config>
device.mk
に行を追加して、ファイルをデバイスのターゲット フォルダsystem/etc/sysconfig/
にコピーします。次に例を示します。PRODUCT_COPY_FILES += <full path to the config file>:system/etc/sysconfig/<new denylist config file>.xml
結果を確認する
結果を確認するには、次のコマンドを実行します。
$ adb shell dumpsys user | grep PACKAGE_SUBSTRING $ adb shell pm list packages --user USER_ID PACKAGE_SUBSTRING $ adb shell cmd user report-system-user-package-whitelist-problems
前提
パッケージをシステム ユーザーにインストールする必要があるかどうかを判断するには、プロジェクト ソースのルートにあるパッケージの AndroidManifest.xml
ファイルを調べます。アプリの属性や、アプリのコンポーネント(すべてのアクティビティ、サービス、ブロードキャスト レシーバ、コンテンツ プロバイダなど)を確認します。詳細については、アプリ マニフェストの概要をご覧ください。
図 1. パッケージ無効化のワークフロー。
レベル 1、アプリレベル
1. アプリ(またはアプリ コンポーネント)がシングルトンとして宣言されているかどうかを確認する
アプリがシングルトンである場合、システムはシステム ユーザーのみでアプリをインスタンス化します。アプリがマルチユーザーを認識するアプリを想定していた可能性が高いと考えられます。マルチユーザーを認識するアプリの詳細については、複数のユーザーを認識するアプリを作成するをご覧ください。
- Android マニフェストで
android:singleUser="true"
を確認します。 true
の場合は、許可リストに含めます。システム ユーザーに必要です。false
の場合は、続行します。削除する前に、他の条件を確認します。
2. そのアプリに保護されたストレージ アクセスが必要かどうかを確認する
システム ブート サービスは、多くの場合、認証情報暗号化(CE)ストレージの代わりにデバイス暗号化(DE)ストレージを使用します。また、ダイレクト ブートに対応したシステムアプリも、デバイス暗号化ストレージを使用します。ダイレクト ブート対応アプリについて詳しくは、システムアプリでのダイレクト ブートをサポートするをご覧ください。
- Android マニフェストで、多数のシステム ブート サービスで必要となる
android:defaultToDeviceProtectedStorage="true"
を確認します。 true
の場合は、許可リストに含めます。false
の場合は、続行します。
レベル 2、アプリ コンポーネント
アクティビティ
アクティビティの詳細については、アクティビティの概要をご覧ください。
a. そのアプリに含まれているのがアクティビティのみであるかどうかを確認する
アクティビティはユーザー インターフェース指向です。Automotive では、システム ユーザーはヘッドレスであるため、人間はシステム ユーザーを操作する必要がありません。そのため、アプリにアクティビティのみが含まれている場合、そのアプリはシステム ユーザーとの関連しない可能性が高いと考えられます。
優先度と特別な権限を確認します。
- アクティビティのみである場合、システム ユーザーで必要になる可能性があります。
- アクティビティのみでない場合、システム ユーザーの許可リストに含めません。
たとえば、互換性テストスイート(CTS)(com.android.cts.priv.ctsshim
)にはアクティビティのみが含まれ、アクティビティはインテント フィルタをテストするように定義されています。ただし、CTS は権限が高いため、テスト目的でシステム ユーザー用にインストールする必要があります。
サービス
サービスの詳細については、サービスの概要をご覧ください。
b. サービスが非公開であると宣言され、他のアプリからアクセスできないかどうかを確認する
サービスを非公開として宣言されている場合、他のパッケージはそのサービスを使用できません。android:exported="false"
を確認します。サービスが非公開として宣言されている、あるいは他のアプリからアクセスできないと宣言されている場合、そのサービスは他のアプリにバインドできません。したがって、以下のステップ c とステップ d は関係ありません。そのため、このコンポーネントでは、そのサービスがシステム ユーザーに必要かどうかに関して、これ以上ヒントが提供されません。
- 宣言されている場合は、次のコンポーネントに進みます。
- 宣言されていない場合は、引き続きこのコンポーネントを確認します。
c. システム ユーザーにインストールされているアプリがこのサービスにバインドされているかどうかを確認する
レベル 1 で許可リストに含まれているパッケージを確認し、バインドされているサービスを特定します。このサービスのインテント フィルタと、他のパッケージ内の startService
からトレースします。
このサービスがシステム ユーザーにインストールされているアプリにバインドされている場合(たとえば、com.android.car.companiondevicesupport
が許可リストに登録され、システム ユーザーで実行される場合)、そのサービスを許可リストに登録します。
- バインドされている場合は、許可リストに含めます。
- 宣言されていない場合は、引き続きこのコンポーネントを確認します。
d. サービスが他のアプリからバインドされ、フォアグラウンドで実行されるように宣言されているかどうかを確認する
startForeground
を確認します。これは、ユーザーがフォアグラウンドでアプリを操作することを意味します。ほとんどの場合、このサービスはシステム ユーザーに不要で、許可リストに含める必要はありません。
- はいの場合は、許可リストに含めないでください。
- 宣言されていない場合は、引き続き次のコンポーネントを確認します。
e. サービスがシステム プロセスで実行されるように定義されているかどうかを確認する
AndroidManifest ファイルで、android:process="system"
を探します。
サービスがシステム プロセスで実行されるように意図的に定義されている場合は、システム サービスと同じプロセスで実行されるため、システム ユーザーで実行されるように許可リストに含める必要があります。Android のメモリ割り当て設計の一部として、システム サービスは強制終了される最終のプロセスです。これは、そうした属性で定義されたサービスが重要であることを示します。Android のメモリ割り当て設計の詳細については、ローメモリ キラーをご覧ください。
- 利用できる場合は、許可リストに含めません。
- 定義されていない場合は、他のコンポーネントを確認します。
たとえば、パッケージ com.android.networkstack.inprocess
には、android:process="system"
タグが付与された RegularMaintenanceJobService
が含まれるため、許可リストに含める必要があります。
コンテンツ プロバイダ
コンテンツ プロバイダの詳細については、コンテンツ プロバイダをご覧ください。
f. システム ユーザーにインストールされたアプリがこのプロバイダに依存しているかどうかを確認する
レベル 1 で許可リストに含まれたパッケージを確認して、依存するプロバイダを確認します。システム ユーザーで実行されているアプリ(例: com.android.car.companiondevicesupport
がシステム ユーザーで実行されるように許可リストに含まれている)が、このコンテンツ プロバイダに依存している場合は、このコンテンツ プロバイダも許可リストに含めてください。
- バインドされている場合は、許可リストに含めます。
- いいえの場合は、許可リストに含めません。
たとえば、com.android.car.EXAMPLE
にシングルトン プロバイダ(SystemActionsContentProvider
と ManagedProvisioningActionsContentProvider
)が含まれている場合、システム ユーザーの許可リストに含める必要があります。次に、com.android.car.EXAMPLE
が WebViewFactoryProvider
の android.webkit
に依存している場合は、android.webkit
を読み込むため、com.android.webview
はシステム ユーザーの許可リストに含める必要があります。
サンプル パッケージのチュートリアル
次の例は、パッケージの AndroidManifest.xml
を評価する方法を示しています。
<?xml version="1.0" encoding="utf-8"?> <!-- 1. Search in the entire manifest for singleUser attribute. No. Move to step 2 --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.providers.calendar" android:sharedUserId="android.uid.calendar"> We can ignore the entire permission section <uses-permission android:name="android.permission.READ_CALENDAR" /> ... <uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" /> <!-- 2. Look for defaultToDeviceProtectedStorage in application's attribute. No. Continue evaluating app components. --> <application android:label="@string/calendar_storage" android:allowBackup="false" android:icon="@drawable/app_icon" android:usesCleartextTraffic="false"> <!-- a. Contain only activities? No. Continue to evaluate components other than activities. --> <provider android:name="CalendarProvider2" android:authorities="com.android.calendar" <!-- b. Is this component exported? Yes. Continue evaluating this component. f. App on u0 might depend on this? Search for CalendarProvider2 in dumpsys, shows ContentProviderRecord{b710923 u0 com.android.providers.calendar/.CalendarProvider2} Yes. Whitelist for system user. --> android:label="@string/provider_label" android:multiprocess="false" android:exported="true" android:readPermission="android.permission.READ_CALENDAR" android:writePermission="android.permission.WRITE_CALENDAR" />
<activity android:name="CalendarContentProviderTests" android:label="Calendar Content Provider" android:exported="false"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.UNIT_TEST" /> </intent-filter> </activity> <!-- Not service/content provider. Ignore. --> <receiver android:name="CalendarProviderBroadcastReceiver" android:exported="false"> <intent-filter> <action android:name="com.android.providers.calendar.intent.CalendarProvider2"/> <category android:name="com.android.providers.calendar"/> </intent-filter> <intent-filter> <action android:name="android.intent.action.EVENT_REMINDER"/> <data android:scheme="content" /> </intent-filter> </receiver> <service android:name="CalendarProviderIntentService"/> </application> </manifest>