Quita paquetes para el usuario del sistema

En esta página, se describe cómo mejorar el rendimiento mediante la identificación y eliminación de paquetes que no son necesarios para el usuario del sistema.

Inhabilita paquetes innecesarios

En Automotive, el usuario del sistema no tiene interfaz gráfica, lo que significa que una persona no debe usarlo ni acceder directamente a él. Como resultado, muchas apps y servicios no necesitan ejecutarse en el usuario del sistema y se pueden inhabilitar para mejorar el rendimiento. Por lo tanto, se proporciona una opción para quitar las apps innecesarias para el usuario del sistema (Usuario 0).

En esta página, se analizan dos tipos de usuarios:

  • SISTEMA. Siempre el usuario 0
  • FULL. Usuario que está diseñado para que lo use una persona (un usuario que no es del sistema), usuario mayor de 10 años

Android 11

En Android 11, cambia la configuración config_userTypePackageWhitelistMode. Las marcas se pueden combinar. En este caso, 5 equivale a 1 más 4 (una combinación de marcas 1 y 4).

Marca Descripción
0 Inhabilitar la lista de entidades permitidas Instala todos los paquetes del sistema, sin registro.
1 Aplicar Instala paquetes del sistema solo cuando están incluidos en la lista de entidades permitidas.
2 Registra paquetes que no estén incluidos en la lista de entidades permitidas.
4 Cualquier paquete que no se mencione en el archivo de la lista de entidades permitidas se incluirá de forma implícita en la lista de entidades permitidas para todos los usuarios.
8 Igual que 4, para el usuario del sistema.
16 Ignora las OTA. No instales paquetes del sistema durante las actualizaciones inalámbricas.

Considera estas situaciones comunes:

  • Para habilitar una función para una lista de entidades permitidas completa, 1 (aplicación forzosa completa)
  • Para habilitar una función en una lista de entidades permitidas incompleta, 5
  • Para habilitar una función para que el usuario de SYSTEM facilite el desarrollo local, usa 9 (lista de entidades permitidas implícita).
  • Para inhabilitar una función como si nunca se hubiera habilitado, 16
  • Para inhabilitar una función y deshacer todos los efectos anteriores, 0

Instala el archivo XML en el directorio sysconfig del dispositivo (es el mismo que contiene el archivo makefile (.mk) que se usó para compilar la imagen del sistema del dispositivo). Cuando asignes un nombre al archivo en formato XML, incluye la ubicación en la que se define el paquete en la compilación, por ejemplo, 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 y Android 10

Para configurar esta función en Android 9 y Android 10, haz lo siguiente:

  1. Superpone la configuración de config_systemUserPackagesBlacklistSupported de frameworks/base/core/res/res/values/config.xml y configúrala en true. Cuando la función está activada, de manera predeterminada, se deben instalar todos los paquetes tanto para el usuario del sistema como para el usuario FULL.
  2. Crea un archivo config.xml que enumere los paquetes que se deben inhabilitar para el usuario del sistema, por ejemplo:
    <config>
        <!-- This package will be uninstalled for the system user -->
        <system-user-blacklisted-app package="com.google.car.calendar" />
    </config>
  3. Agrega una línea a device.mk para copiar el archivo en la carpeta de destino system/etc/sysconfig/ del dispositivo, por ejemplo:
    PRODUCT_COPY_FILES += <full path to the config file>:system/etc/sysconfig/<new denylist config file>.xml

Verifica el resultado

Para verificar el resultado, ejecuta el siguiente comando:

$ 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

Establecimiento

Para determinar si un paquete se debe instalar en el usuario del sistema, examina el archivo AndroidManifest.xml del paquete ubicado en la raíz de la fuente del proyecto, incluidos los atributos y los componentes de la app, que incluyen todas las actividades, los servicios, los receptores de emisión y los proveedores de contenido. Para obtener más información, consulta Descripción general del manifiesto de la app.

Inhabilita el flujo de trabajo de paquetes

Figura 1: Inhabilita el flujo de trabajo de paquetes.

Nivel 1, nivel de la app

1. Verifica si la app (o sus componentes) se declaró como un singleton

Si la app es un singleton, el sistema crea una instancia de la app solo en el usuario del sistema. Es probable que la app se haya diseñado para varios usuarios. Para obtener más información sobre las apps para varios usuarios, consulta Cómo compilar apps para varios usuarios.

  1. Busca android:singleUser="true" en el manifiesto de Android.
  2. Si es true, se agrega a la lista de entidades permitidas. Necesaria para el usuario del sistema.
  3. Si es false, continúa. Verifica otros criterios antes de quitarlos.

2. Cómo comprobar si la app requiere acceso al almacenamiento protegido

Muchos servicios de inicio del sistema a menudo dependen del almacenamiento encriptado por dispositivo (DE) en lugar del almacenamiento encriptado por credenciales (CE). Además, las apps del sistema que son compatibles con el inicio directo también dependen del almacenamiento encriptado del dispositivo. Para obtener más información sobre las apps que admiten el inicio directo, consulta Cómo admitir el inicio directo en las apps del sistema.

  1. Verifica el manifiesto de Android en busca de android:defaultToDeviceProtectedStorage="true", que es necesario para varios servicios de inicio del sistema.
  2. Si es true, inclúyelo en la lista de entidades permitidas.
  3. Si es false, continúa.

Nivel 2, componentes de la app

Actividades

Para obtener más información sobre las actividades, consulta Introducción a las actividades.

a. Cómo comprobar si la app solo contiene actividades

Las actividades están orientadas a la interfaz de usuario. Como el usuario del sistema no tiene interfaz gráfica en Automotive, ninguna persona debe interactuar con él. Como resultado, si la app solo contiene actividades, es probable que sea irrelevante para el usuario del sistema.

Verifica si hay privilegios especiales y de prioridad:

  1. Si se muestra Yes, es posible que el usuario del sistema lo necesite.
  2. Si la respuesta es No, no incluyas una lista de entidades permitidas para el usuario del sistema.

Por ejemplo, el Compatibility Test Suite (CTS) (com.android.cts.priv.ctsshim) solo contiene actividades, y las actividades se definen para probar filtros de intents. Sin embargo, como CTS tiene un privilegio alto, debe instalarse para el usuario del sistema con fines de prueba.

Servicio

Para obtener más información sobre los servicios, consulta Descripción general de los servicios.

b. Comprueba si el servicio se declaró como privado y si no se puede acceder a él desde otras apps

Si el servicio se declara como privado, los demás paquetes no lo usarán. Busca android:exported="false". Si el servicio se declara como privado o no se puede acceder a él desde otras apps, no se puede vincular a otras apps. Por lo tanto, los pasos c y d a continuación son irrelevantes. Como resultado, este componente no proporcionaría más sugerencias sobre si el servicio es necesario para el usuario del sistema.

  • Si la respuesta es , verifica el siguiente componente.
  • Si la respuesta es No, continúa verificando este componente.

c. Verifica si el usuario de las apps instaladas en el sistema se puede vincular a este servicio

Busca paquetes en la lista de entidades permitidas del nivel 1 y, luego, identifica los servicios a los que están vinculados. Genera un registro desde el filtro de intents en este servicio y startService en otros paquetes.

Si este servicio está vinculado a apps instaladas en el usuario del sistema (por ejemplo, com.android.car.companiondevicesupport está en la lista de entidades permitidas para ejecutarse en el usuario del sistema), agrega el servicio a la lista de entidades permitidas:

  • Si la respuesta es , agrégalo a la lista de entidades permitidas.
  • Si la respuesta es No, continúa verificando este componente.

d. Verifica si el servicio está vinculado desde otras apps y se declaró para que se ejecute en primer plano

Busca startForeground. Esto significa que las personas interactuarían con la app en primer plano. Lo más probable es que este servicio no sea necesario para el usuario del sistema y que no esté incluido en la lista de entidades permitidas:

  • Si la respuesta es , no incluyas el dominio en la lista de entidades permitidas.
  • Si la respuesta es No, continúa verificando el siguiente componente.

e. Comprueba si el servicio está definido para ejecutarse en el proceso del sistema

En el archivo AndroidManifest, busca android:process="system". Si el servicio se define de forma intencional para que se ejecute en el proceso del sistema, se ejecutará en el mismo proceso que el servicio del sistema y debería incluirse en la lista de entidades permitidas para que se ejecute en el usuario del sistema. Como parte del diseño de asignación de memoria de Android, los servicios del sistema son algunos de los últimos procesos que se cancelan, lo que implica la criticidad de los servicios definidos con ese atributo. Para obtener más información sobre el diseño de asignación de memoria de Android, consulta Eliminador de poca memoria.

  • Si la respuesta es , no lo incluyas en la lista de entidades permitidas.
  • Si la respuesta es No, continúa verificando otros componentes.

Por ejemplo, el paquete com.android.networkstack.inprocess debe estar en la lista de entidades permitidas porque contiene RegularMaintenanceJobService, que tiene la etiqueta android:process="system".

Proveedor de contenido

Para obtener más información sobre los proveedores de contenido, consulta Proveedores de contenido.

f. Comprueba si la app instalada en el sistema del usuario depende de este proveedor

Busca paquetes incluidos en la lista de entidades permitidas del nivel 1 y verifica de qué proveedores dependen. Si una app que se ejecuta en el usuario del sistema (por ejemplo, com.android.car.companiondevicesupport está incluida en la lista de entidades permitidas para ejecutarse en el usuario del sistema) y depende de este proveedor de contenido, asegúrate de que este también esté incluido en la lista de entidades permitidas.

  1. Si la respuesta es , incluye en la lista de entidades permitidas.
  2. Si la respuesta es No, no la incluyas en la lista de entidades permitidas.

Por ejemplo, si com.android.car.EXAMPLE contiene proveedores singleton (SystemActionsContentProvider y ManagedProvisioningActionsContentProvider), debería estar incluido en la lista de entidades permitidas del usuario del sistema. Luego, si com.android.car.EXAMPLE depende de android.webkit para WebViewFactoryProvider, com.android.webview debe estar en la lista de entidades permitidas para el usuario del sistema, ya que carga android.webkit.

Explicación del paquete de muestra

En el siguiente ejemplo, se muestra cómo evaluar el AndroidManifest.xml de un paquete:

<?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>