This page describes how to improve performance by identifying and removing packages that aren't needed for the system user.
Disable unnecessary packages
In Automotive, the system user is headless, which means the system user isn't intended to be used or directly accessed by a human. As a result, many apps and services don't need to run in the system user and can be disabled to improve performance. Therefore, an option is provided to remove unnecessary apps for the system user (User 0).
On this page, two types of users are discussed:
- SYSTEM. Always User 0
- FULL. User that is intended to be used by a human (a non-system user), User 10+
Android 11
In Android 11, change the config_userTypePackageWhitelistMode
configuration. Flags can be combined. In this case, 5
equates to 1
plus 4
(a combination of flags 1
and 4
).
Flag | Description |
---|---|
0 |
Disable allowlist. Install all system packages; no logging. |
1 |
Enforce. Install system packages only when they're allowlisted. |
2 |
Log non-allowlisted packages. |
4 |
Any package not mentioned in the allowlist file is implicitly allowlisted for all users. |
8 |
Same as 4 , for the system user. |
16 |
Ignore OTAs. Don't install system packages during OTAs. |
Consider these common scenarios:
- To enable a feature for a complete allowlist,
1
(fully enforced) - To enable a feature for an incomplete allowlist,
5
- To enable a feature for the
SYSTEM
user to ease local development,9
(implicit allowlist) - To disable a feature as though it had never been enabled,
16
- To disable a feature and undo all previous effects,
0
Install the XML file in the sysconfig
directory for the device
(this is the same directory that contains the makefile (.mk
) used to build the
system image for the device). When you name the XML file, include the location
where the package is defined in the build, for example, 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 and Android 10
To configure this feature in Android 9 and Android 10:
- Overlay the
config_systemUserPackagesBlacklistSupported
config fromframeworks/base/core/res/res/values/config.xml
and set it totrue
. When the feature is turned on, by default, all packages should be installed for both the system user and the FULL user. - Create a
config.xml
file listing which packages should be disabled for the system user, for example:<config> <!-- This package will be uninstalled for the system user --> <system-user-blacklisted-app package="com.google.car.calendar" /> </config>
- Add a line to
device.mk
to copy the file to the device's target foldersystem/etc/sysconfig/
, for example:PRODUCT_COPY_FILES += <full path to the config file>:system/etc/sysconfig/<new denylist config file>.xml
Verify the result
To verify the result, run:
$ 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
Premise
To determine if a package should be installed in the system user, examine the
package's AndroidManifest.xml
file located at the root of the
project source, including the app's attributes and the components of the
app, which include all activities, services, broadcast receivers, and content
providers. To learn more, see
App
manifest overview.
Figure 1. Disable packages workflow.
Level 1, app level
1. Check if app (or app components) is declared as a singleton
If the app is a singleton, the system instantiates the app in the system user only. It's likely the app was intended to be a multiuser-aware app. To learn more about multiuser-aware apps, see Build multiuser-aware apps.
- Check the Android manifest for
android:singleUser="true"
. - If
true
, allowlist. Needed for the system user. - If
false
, continue. Check other criteria before removing.
2. Check if the app requires protected storage access
Many system boot services often rely on device encrypted (DE) storage instead of credential encrypted (CE) storage. Also, system apps that are direct boot aware also rely on device encrypted storage. To learn more about direct boot aware apps, see Support Direct Boot in system apps.
- Check the Android manifest for
android:defaultToDeviceProtectedStorage="true"
, which is needed for numerous system boot services. - If
true
, allowlist. - If
false
, continue.
Level 2, app components
Activities
To learn more about activities, see Introduction to activities.
a. Check if the app contains only activities
Activities are user interface oriented. Because the system user is headless in Automotive, no human should be interacting with the system user. As a result, if the app contains activities only, the app is most likely irrelevant to the system user.
Check for priority and special privilege:
- If Yes, might be needed for the system user.
- If No, don't allowlist for the system user.
For example, the Compatibility Test Suite (CTS)
(com.android.cts.priv.ctsshim
) contains only activities, and
activities are defined to test intent filters. However, because CTS has a high
privilege, it needs to be installed for the system user for testing purposes.
Service
To learn more about services, see Services overview.
b. Check if service is declared as private and can't be accessed from other apps
If the service is declared as private, other packages won't use the
service. Look for android:exported="false"
. If the service is declared
as private or can't be accessed from other apps, then it can't be bound by
other apps. Therefore, Step c and Step d below are irrelevant. As a result,
this component wouldn't provide more hints as to whether the service is needed
for the system user.
- If Yes, check the next component.
- If No, continue to check this component.
c. Check if apps installed in system user might bind to this service
Check for allowlisted packages in Level 1 and identify the services
they're bound to. Trace from the intent filter in this service and startService
in other packages.
If this service is bound to apps installed in the system user (for example,
com.android.car.companiondevicesupport
is allowlisted to run in the
system user), then allowlist the service:
- If Yes, allowlist.
- If No, continue to check this component.
d. Check if service is bound from other apps and declared to run in foreground
Look for startForeground
. This means people would be interacting with
the app in the foreground. Most likely, this service wouldn't be needed for the
system user and need not be allowlisted:
- If Yes, don't allowlist.
- If No, continue to check the next component.
e. Check if service is defined to run in system process
In the AndroidManifest file, look for android:process="system"
.
If the service is intentionally defined to run in the system process, then
it runs in the same process as the system service and
should be allowlisted to run in the system user. As part of Android's memory
allocation design, system services are some of the last processes to be killed,
which implies the criticality of services defined with such an attribute. To
learn more about Android's memory allocation design, see Low-memory
killer.
- If Yes, don't allowlist.
- If No, continue to check other components.
For example, package com.android.networkstack.inprocess
must be
allowlisted because it contains RegularMaintenanceJobService
, which
has the android:process="system"
tag.
Content provider
To learn more about content providers, see Content providers.
f. Check if app installed in system user depends on this provider
Check for allowlisted packages in Level 1 and check which providers they
depend on. If an app running in the system user (for example,
com.android.car.companiondevicesupport
is allowlisted to run in the
system user) and depends on this content provider, then ensure that this content
provider is also allowlisted.
- If Yes, allowlist.
- If No, don't allowlist.
For example, if com.android.car.EXAMPLE
contains singleton
providers (SystemActionsContentProvider
and
ManagedProvisioningActionsContentProvider
), it should be
allowlisted for the system user. Then, if com.android.car.EXAMPLE
depends on android.webkit
for WebViewFactoryProvider
,
then com.android.webview
must be allowlisted for the system user
given that it loads android.webkit
.
Sample package walkthrough
The following example shows how to evaluate the AndroidManifest.xml
of a
package:
<?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>