Remove packages for the system user

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:

  1. Overlay the config_systemUserPackagesBlacklistSupported config from frameworks/base/core/res/res/values/config.xml and set it to true. When the feature is turned on, by default, all packages should be installed for both the system user and the FULL user.
  2. 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>
  3. Add a line to device.mk to copy the file to the device's target folder system/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.

Disable packages workflow

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.

  1. Check the Android manifest for android:singleUser="true".
  2. If true, allowlist. Needed for the system user.
  3. 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.

  1. Check the Android manifest for android:defaultToDeviceProtectedStorage="true", which is needed for numerous system boot services.
  2. If true, allowlist.
  3. 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:

  1. If Yes, might be needed for the system user.
  2. 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.

  1. If Yes, allowlist.
  2. 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>