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, são discutidos dois tipos de usuários:

  • SYSTEM. Sempre o 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 de flags 1 e 4).

Sinalização Descrição
0 Desativar a lista de permissões. Instala todos os pacotes do sistema, sem registro.
1 Aplicar. Instale pacotes do sistema somente quando eles estiverem na lista de permissões.
2 Registrar pacotes não permitidos.
4 Qualquer pacote não mencionado no arquivo de lista de permissões é adicionado implicitamente à lista de permissões de todos os usuários.
8 Igual a 4, para o usuário do sistema.
16 Ignorar OTAs. Não instale pacotes do sistema durante OTAs.

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. Sobreponha a configuração config_systemUserPackagesBlacklistSupported de frameworks/base/core/res/res/values/config.xml e defina-a como true. Quando o recurso é ativado, por padrão, todos os pacotes precisam ser instalados para o usuário do sistema e 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 a device.mk para copiar o arquivo para a pasta de destino system/etc/sysconfig/ do dispositivo, 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 a 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 app for um singleton, o sistema instanciará 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, na sigla em inglês) em vez do armazenamento criptografado por credenciais (CE, na sigla em inglês). Além disso, os apps do sistema que são compatíveis com a inicialização direta 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 do app

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 é headless no Automotive, nenhum humano pode interagir com ele. Como resultado, se o app contém apenas atividades, ele provavelmente é irrelevante para o usuário do sistema.

Verifique se há prioridade e privilégio especial:

  1. Se Sim, talvez seja 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 privilégio, 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 é declarado como particular e não pode ser acessado de outros apps

Se o serviço for declarado como privado, outros pacotes não vão usar 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 a resposta for Sim, verifique o próximo componente.
  • Se a resposta for Não, continue verificando esse componente.

c. Verificar se os apps instalados no usuário do sistema podem se vincular a esse serviço

Verifique se há pacotes na lista de permissões no nível 1 e identifique os serviços a que eles estão vinculados. Rastreamento 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 a resposta for Sim, adicione à 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 estariam interagindo com o app em primeiro plano. Provavelmente, esse serviço não será necessário para o 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 ser executado no processo do sistema, ele será executado no mesmo processo que o serviço do sistema e precisará ser incluído na lista de permissões para ser executado no usuário do sistema. Como parte do design de alocação de memória do Android, os serviços do sistema são alguns dos últimos processos a serem encerrados, o que implica a criticidade dos serviços definidos com esse atributo. Para saber mais sobre o design de alocação de memória do Android, consulte O que é o recurso de encerramento de apps com pouca memória.

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

Por exemplo, o pacote com.android.networkstack.inprocess precisa estar 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

Verifique se há pacotes na lista de permissões do nível 1 e verifique de quais provedores eles dependem. Se um app 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 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 adicione à lista de permissões.

Por exemplo, se com.android.car.EXAMPLE contiver provedores Singleton (SystemActionsContentProvider e ManagedProvisioningActionsContentProvider), ele precisará ser incluído 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>