Removing Packages for the System User

This article describes how to improve performance by identifying and removing packages that are not needed for the SYSTEM User.

Disabling unnecessary packages

In Automotive, the SYSTEM User is headless, which means the SYSTEM User is not intended to be used or directly accessed by a human. As a result, many apps and services need not 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).

In this article, 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, you change the configuration, config_userTypePackageWhitelistMode. 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 are 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

Be sure to 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 at which 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 application'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, Application level

1. Check if app (or app components) is declared as a singleton

If the application is a singleton, the system will instantiate the app in the SYSTEM User only. It's likely the app was intended to be a multiuser-aware app. To learn more about multi-user aware apps, see Building 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 applications that are direct boot aware also rely on device encrypted storage. To learn more about direct boot aware apps, see Supporting Direct Boot in system applications.

  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, Application components

Activities

To learn more about activities, see Introduction to Activities.

a. Check if the app only contains Activities

Activities are user interface-oriented. Since 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 not relevant to the SYSTEM User.

Check for priority and special privilege.

  1. If Yes, perhaps needed for the SYSTEM User.
  2. If No, do not 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, since it 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 cannot be accessed from other applications

If the service is declared as private, other packages will not use the service. Look for android:exported="false". If the service is declared as private or cannot be accessed from other applications, then it cannot be bound by other applications. Therefore, Step C and Step D below are irrelevant. As a result, this component would not provide more hints as to whether or not the service is needed for the SYSTEM User.

  1. If Yes, check the next component.
  2. If No, continue to check this component.

c. Check if applications installed in SYSTEM User might bind to this service

Check for allowlisted packages in Level 1 and identify the services to which they are bound. 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.

  1. If Yes, allowlist.
  2. If No, continue to check this component.

d. Check if service is bound from other applications 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 would not be needed for the SYSTEM User and need not be allowlisted.

  1. If Yes, do not allowlist.
  2. If No, continue to check the next component.

e. Check if service is defined to run in system process

In the AndroidManifest, look for android:process="system".
If the service is intentionally defined to run in the system process, then it means it explicitly will run 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.

  1. If Yes, do not allowlist.
  2. If No, continue to check other components.

For example, package com.android.networkstack.inprocess must be allowlisted since it contains RegularMaintenanceJobService, which has the android:process="system" tag.

Content provider

To learn more about content providers, see Content providers.

f. Check if application installed in SYSTEM User depends on this provider

Check for allowlisted packages in Level 1 and check which providers they depend on. If an application 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, do not 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 the android.webkit.

Sample package walk-through

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>