Remover pacotes para o usuário do sistema

Esta página descreve como melhorar o desempenho identificando e removendo pacotes que não são necessários para o usuário do sistema.

Desativar pacotes desnecessários

No Automotive, o usuário do sistema é headless, o que significa que ele não foi projetado para ser usado ou acessado diretamente por humanos. Como resultado, muitos apps e serviços não precisam ser executados no usuário do sistema e podem ser desativados para melhorar o desempenho. Portanto, há uma opção para remover apps desnecessários para o usuário do sistema (Usuário 0).

Nesta página, abordamos dois tipos de usuários:

  • SYSTEM. Sempre usuário 0
  • FULL. Usuário que deve ser usado por uma pessoa (um usuário não do sistema), Usuário 10+

Android 11

No Android 11, mude a configuração config_userTypePackageWhitelistMode. As flags podem ser combinadas. Nesse caso, 5 equivale a 1. mais 4 (uma combinação das sinalizações 1 e 4).

Sinalização Descrição
0 Desativar lista de permissões. Instala todos os pacotes do sistema, sem registro.
1 Aplicar. Instalar pacotes do sistema apenas quando eles estiverem na lista de permissões.
2 Registra pacotes que não estão na lista de permissões.
4 Todos os pacotes não mencionados no arquivo da lista de permissões são implicitamente permitidos para todos os usuários.
8 Igual a 4, para o usuário do sistema.
16 Ignorar OTAs. Não instale pacotes do sistema durante atualizações OTA.

Considere estes cenários comuns:

  • Para ativar um recurso para uma lista de permissões completa, 1 (aplicação total)
  • Para ativar um recurso para uma lista de permissões incompleta, 5
  • Para ativar um recurso para que o usuário SYSTEM facilite o desenvolvimento local, 9 (lista de permissões implícitas)
  • Para desativar um recurso como se ele nunca tivesse sido ativado, 16
  • Para desativar um recurso e desfazer todos os efeitos anteriores, 0

Instale o arquivo XML no diretório sysconfig do dispositivo, que é o mesmo que contém o makefile (.mk) usado para criar a imagem do sistema do dispositivo. Ao nomear o arquivo XML, inclua o local em que o pacote é definido no build, por exemplo, 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 e Android 10

Para configurar esse recurso no Android 9 e no Android 10:

  1. Sobrepor a config_systemUserPackagesBlacklistSupported de configuração de frameworks/base/core/res/res/values/config.xml e defina para true. Quando o recurso está ativado, por padrão, todos os pacotes deve ser instalado para o usuário do sistema e para o usuário FULL.
  2. Crie um arquivo config.xml que liste quais pacotes precisam ser desativados para o usuário do sistema, por exemplo:
    <config>
        <!-- This package will be uninstalled for the system user -->
        <system-user-blacklisted-app package="com.google.car.calendar" />
    </config>
  3. Adicione uma linha ao device.mk para copiar o arquivo para o pasta de destino system/etc/sysconfig/, por exemplo:
    PRODUCT_COPY_FILES += <full path to the config file>:system/etc/sysconfig/<new denylist config file>.xml

Verificar o resultado

Para verificar o resultado, execute:

$ 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

Premissa

Para determinar se um pacote precisa ser instalado no usuário do sistema, examine o arquivo AndroidManifest.xml do pacote localizado na raiz da origem do projeto, incluindo os atributos e os componentes do app, que incluem todas as atividades, serviços, broadcast receivers e provedores de conteúdo. Para saber mais, consulte Visão geral do manifesto do app.

Desativar o fluxo de trabalho de pacotes

Figura 1. Desativar o fluxo de trabalho de pacotes.

Nível 1, nível do app

1. Verificar se o app (ou os componentes dele) está declarado como um singleton

Se o aplicativo for um singleton; o sistema instancia o app apenas no usuário do sistema. É provável que o app tenha sido criado para ser multiusuário. Para saber mais sobre apps multiusuário, consulte Criar apps multiusuário.

  1. Verifique o manifesto do Android para android:singleUser="true".
  2. Se true, adicione à lista de permissões. Necessário para o usuário do sistema.
  3. Se false, continue. Verifique outros critérios antes de remover.

2. Verificar se o app precisa de acesso ao armazenamento protegido

Muitos serviços de inicialização do sistema geralmente dependem do armazenamento criptografado do dispositivo (DE). do armazenamento criptografado por credenciais (CE). Além disso, os apps do sistema que são com reconhecimento de inicialização também dependem do armazenamento criptografado do dispositivo. Para saber mais sobre apps compatíveis com a inicialização direta, consulte Suporte à inicialização direta em apps do sistema.

  1. Verifique o manifesto do Android para android:defaultToDeviceProtectedStorage="true", que é necessário para vários serviços de inicialização do sistema.
  2. Se true, adicione à lista de permissões.
  3. Se false, continue.

Nível 2, componentes de apps

Atividades

Para saber mais sobre atividades, consulte Introdução às atividades.

a. Verificar se o app contém apenas atividades

As atividades são orientadas pela interface do usuário. Como o usuário do sistema é sem comando no Automotive, nenhum humano pode interagir com ele. Como resultado, se o aplicativo tiver somente atividades, ele será provavelmente irrelevante para o usuário do sistema.

Verifique se há prioridade e privilégio especial:

  1. Se Sim, pode ser necessário para o usuário do sistema.
  2. Se a resposta for Não, não inclua o usuário do sistema na lista de permissões.

Por exemplo, o conjunto de testes de compatibilidade (CTS) (com.android.cts.priv.ctsshim) contém apenas atividades, e as atividades são definidas para testar filtros de intent. No entanto, como o CTS tem um alto ele precisa ser instalado para o usuário do sistema para fins de teste.

Serviço

Para saber mais sobre os serviços, consulte Visão geral dos serviços.

b. Verificar se o serviço foi declarado como particular e não pode ser acessado de outros apps

Se o serviço for declarado como privado, outros pacotes não usarão o serviço. Procure por android:exported="false". Se o serviço for declarado como privado ou não puder ser acessado por outros apps, ele não poderá ser vinculado a outros apps. Portanto, as etapas c e d abaixo são irrelevantes. Como resultado, esse componente não fornece mais dicas sobre se o serviço é necessário para o usuário do sistema.

  • Se Sim, verifique o próximo componente.
  • Se a resposta for Não, continue verificando esse componente.

c. Conferir se os apps instalados no usuário do sistema podem ser vinculados a este serviço

Procure pacotes na lista de permissões no nível 1 e identifique os serviços às quais eles estão vinculados. Trace do filtro de intent neste serviço e startService em outros pacotes.

Se esse serviço estiver vinculado a apps instalados no usuário do sistema (por exemplo, com.android.car.companiondevicesupport está na lista de permissões para ser executado no usuário do sistema), adicione o serviço à lista de permissões:

  • Se Sim, coloque na lista de permissões.
  • Se a resposta for Não, continue verificando esse componente.

d. Verificar se o serviço está vinculado a outros apps e declarado para ser executado em primeiro plano

Procure por startForeground. Isso significa que as pessoas vão interagir com o app em primeiro plano. Muito provavelmente, esse serviço não seria necessário para a usuário do sistema e não precisa estar na lista de permissões:

  • Se a resposta for Sim, não adicione à lista de permissões.
  • Se a resposta for Não, continue verificando o próximo componente.

e. Verificar se o serviço está definido para ser executado no processo do sistema

No arquivo AndroidManifest, procure android:process="system". Se o serviço for definido intencionalmente para execução no processo do sistema, ele é executado no mesmo processo que o serviço do sistema e precisa estar na lista de permissões para execução no usuário do sistema. Como parte da memória do Android design de alocação, serviços do sistema são alguns dos últimos processos a serem encerrados, o que implica a importância dos serviços definidos com esse atributo. Para saber mais sobre o design de alocação de memória do Android, consulte Low-memory killer.

  • Se Sim, não coloque na lista de permissões.
  • Se a resposta for Não, continue verificando os outros componentes.

Por exemplo, o pacote com.android.networkstack.inprocess precisa ser está na lista de permissões porque contém RegularMaintenanceJobService, que tem a tag android:process="system".

Provedor de conteúdo

Para saber mais sobre provedores de conteúdo, consulte Provedores de conteúdo.

f. Verificar se o app instalado no usuário do sistema depende desse provedor

Procure pacotes na lista de permissões no nível 1 e confira os provedores dependerão dele. Se um aplicativo em execução no usuário do sistema (por exemplo, com.android.car.companiondevicesupport está na lista de permissões para execução no usuário do sistema) e depende desse provedor de conteúdo, verifique se esse conteúdo provedor também está na lista de permissões.

  1. Se a resposta for Sim, adicione à lista de permissões.
  2. Se a resposta for Não, não coloque na lista de permissões.

Por exemplo, se com.android.car.EXAMPLE contiver singleton provedores (SystemActionsContentProvider e ManagedProvisioningActionsContentProvider), ele deve ser na lista de permissões para o usuário do sistema. Se com.android.car.EXAMPLE depender de android.webkit para WebViewFactoryProvider, com.android.webview precisa estar na lista de permissões permitidas para o usuário do sistema, já que ele carrega android.webkit.

Exemplo de tutorial de pacote

O exemplo a seguir mostra como avaliar o AndroidManifest.xml de um pacote:

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