Os processos de apps no Android não existem isoladamente. Os aplicativos geralmente dependem de serviços fornecidos por outros aplicativos ou pelo próprio sistema. Quando um processo se conecta a outro por uma vinculação de serviço, ele cria uma dependência que tem um impacto profundo na forma como o framework Android gerencia a memória.
Estados de processo e pontuações de falta de memória
O framework Android usa estados de processo para acompanhar a importância de cada
processo em execução. Esses estados são usados pelo OomAdjuster para atribuir um valor de ajuste de pontuação de OOM (oom_score_adj), que varia de -1.000 a 1.000.
Um valor oom_score_adj menor significa que o processo é mais importante e tem menos probabilidade de ser encerrado pelo Low Memory Killer (LMK).
Estados comuns do processo
A tabela a seguir mostra alguns dos estados de processo mais comuns e os valores típicos de oom_score_adj. Para uma lista completa e atualizada, consulte
android.app.ActivityManager e com.android.server.am.psc.Constants no
código-fonte do Android.
| Estado do processo (abreviação) | Descrição | oom_score_adj típico |
|---|---|---|
| PER (persistente) | Processos do sistema que precisam ser executados sempre (por exemplo, telefonia). | -800 |
| TOP | O processo com que o usuário está interagindo no momento. | 0 |
| VIS (visível) | O processo tem uma atividade visível (por exemplo, atrás de uma caixa de diálogo translúcida). | 100 |
| PERC (perceptível) | Processo em segundo plano de que o usuário tem conhecimento (por exemplo, reprodução de música). | 200 |
| FGS | Processo que hospeda um serviço em primeiro plano. | 0 a 200 (varia) |
| BTOP (Bound Top) | Processo vinculado a um aplicativo TOP. | 100 |
| BFGS | Serviço em primeiro plano vinculado (normalmente vinculado ao sistema). | 0 |
| PREV (Anterior) | O último processo em que o usuário estava antes do atual. | 700 |
| EM CACHE | Apps em segundo plano que podem ser encerrados com segurança. | 900 a 999 |
O impacto das vinculações de serviço
Quando um processo cliente (por exemplo, um app no estado TOP) se vincula a um serviço em um
processo de servidor, o processo de servidor geralmente herda uma prioridade elevada. Isso garante que o serviço permaneça disponível enquanto o cliente precisar dele.

Como controlar a herança com flags do BIND
A herança é o comportamento padrão ao usar Context.BIND_AUTO_CREATE.
No entanto, os desenvolvedores podem controlar como a vinculação afeta a importância do processo de destino
usando várias flags em bindService().
Principais flags BIND para pontuação OOM
As flags a seguir são mais relevantes ao gerenciar a pressão da memória em todo o sistema:
BIND_AUTO_CREATE: a flag mais comum. Ele garante que o processo de serviço seja iniciado e mantido ativo enquanto a vinculação existir. Por padrão, ele também eleva a prioridade do processo do servidor para corresponder à do cliente.BIND_NOT_FOREGROUND: impede que o processo do serviço de destino seja elevado à prioridade de programação em primeiro plano (prioridade da CPU). No entanto, ele ainda permite que a prioridade de memória (oom_score_adj) seja elevada. Isso é útil para trabalhos em segundo plano que não devem competir com a interface do usuário por ciclos de CPU, mas ainda precisam ser protegidos contra encerramento.BIND_WAIVE_PRIORITY: uma flag muito forte que instrui o sistema a não afetar a prioridade de agendamento ou gerenciamento de memória do processo de destino. O processo de serviço será gerenciado como se fosse um processo em segundo plano regular na lista LRU, tornando-o qualificado para eliminação por falta de memória, mesmo enquanto vinculado.BIND_ABOVE_CLIENT: indica que o serviço é mais importante do que o app cliente em si. Quando o sistema precisa recuperar memória, ele prefere encerrar o app cliente antes do serviço vinculado. Isso é "mais forte" do queBIND_AUTO_CREATE, porque oferece uma camada extra de proteção para o serviço às custas do cliente.BIND_NOT_PERCEPTIBLE: reduz a importância do serviço de destino para abaixo do nívelPERCEPTIBLE, permitindo que o sistema recupere a memória para abrir espaço para processos mais críticos perceptíveis ao usuário.
Na prática: como observar os efeitos de vinculação
Vamos usar o aplicativo MemoryLab para demonstrar como uma vinculação de um
app TOP afeta o estado de um processo separado.
1. Iniciar o MemoryLab
O comando a seguir inicia o app. Depois que ele abrir, verifique se o app permanece em primeiro plano (não pressione o botão home nem mude de app ainda).
adb shell am start -n com.android.memorylab/.MainActivity
2. Identificar processos
Verifique os estados do processo antes da vinculação. O MemoryLab executa a interface principal em um processo e tem um RemoteService que é executado em um processo :remote.
adb shell dumpsys activity processes com.android.memorylab
Exemplo de snippet de saída:
Process OOM control (154 total, non-act at 7, non-svc at 7):
Proc #0: fg T/A/TOP LCMNFUATI t: 0 13470:com.android.memorylab/u0a417 (top-activity)
oom: max=1001 curRaw=0 setRaw=0 cur=0 set=0
state: cur=TOP set=TOP lastRss=0.00 lastCachedRss=0.00
Você vai ver o processo principal com.android.memorylab no estado TOP. O processo :remote ainda não foi iniciado.
3. Vinculação de gatilho
Envie uma transmissão para o app para acionar a vinculação de serviço:
adb shell am broadcast -a com.android.memorylab.LEAK_BINDER
4. Observar estado elevado
Verifique os estados do processo novamente:
adb shell dumpsys activity processes | grep -A 10 "com.android.memorylab"
Exemplo de snippet de saída:
Proc # 1: vis F/ /BTOP ---NFUATI t: 0 13560:com.android.memorylab:remote/u0a417 (service)
com.android.memorylab/.RemoteService<=Proc{13470:com.android.memorylab/u0a417}
oom: max=1001 curRaw=100 setRaw=100 cur=100 set=100
state: cur=BTOP set=BTOP lastRss=0.00 lastCachedRss=0.00
O processo :remote está em execução e no estado BTOP (Bound TOP) com um oom_score_adj de 100. Isso é muito mais protegido do que um serviço em segundo plano típico, que estaria em 500 ou mais. A notação <=Proc{...} mostra qual processo é responsável por essa elevação de prioridade.
5. Enviar para segundo plano
Pressione o botão HOME no dispositivo. Verifique os estados novamente:
adb shell dumpsys activity processes | grep -A 10 "com.android.memorylab"
Exemplo de snippet de saída:
Proc # 2: prev b/ /LAST --------I t: 0 13560:com.android.memorylab:remote/u0a417 (service)
com.android.memorylab/.RemoteService<=Proc{13470:com.android.memorylab/u0a417}
oom: max=1001 curRaw=700 setRaw=700 cur=700 set=700
state: cur=LAST set=LAST lastRss=0.00 lastCachedRss=0.00
Proc # 1: prev b/ /LAST --------I t: 0 13470:com.android.memorylab/u0a417 (previous)
oom: max=1001 curRaw=700 setRaw=700 cur=700 set=700
state: cur=LAST set=LAST lastRss=209MB lastCachedRss=0.00
Agora, os dois processos mudaram para um estado de prioridade mais baixa (PREV /
oom_score_adj 700), porque o processo do cliente não é mais TOP. Observação:
LAST no despejo de estado se refere ao estado interno LAST_ACTIVITY, que
corresponde a PREV nos resumos de alto nível.
Analisar com procstats
A ferramenta procstats oferece uma visão histórica desses estados.
# View stats for MemoryLab over the last hour
adb shell dumpsys procstats --hours 1 com.android.memorylab
Exemplo de snippet de saída:
* com.android.memorylab / u0a417 / v37:
* Prc com.android.memorylab / u0a417 / v37:
TOTAL: 0.89% (0.00-0.00-0.00/0.00-0.00-0.00/210MB-210MB-210MB over 1)
Top: 0.89% (0.00-0.00-0.00/0.00-0.00-0.00/210MB-210MB-210MB over 1)
* Prc com.android.memorylab:remote / u0a417 / v37:
TOTAL: 0.19%
Bnd Top: 0.19%
Aqui, Bnd Top indica a porcentagem de tempo que o processo remoto passou
vinculado a um aplicativo no estado TOP.
Capturar e analisar vinculações com o Perfetto
Enquanto o dumpsys oferece um instantâneo, o Perfetto permite ver o momento exato em que uma vinculação ocorre e como a pontuação OOM muda em tempo real.
1. Gravar um rastro
Use uma configuração que inclua linux.process_stats e a categoria am do atrace:
adb shell perfetto -c - --txt -o /data/misc/perfetto-traces/service_bindings.perfetto-trace <<EOF
buffers: { size_kb: 65536 }
data_sources: {
config {
name: "linux.process_stats"
process_stats_config { proc_stats_poll_ms: 100 }
}
}
data_sources: {
config {
name: "linux.ftrace"
ftrace_config { ftrace_events: "am/am_proc_bound" }
}
}
duration_ms: 15000
EOF
2. Transições de pontuação de OOM de consulta
Com o PerfettoSQL, é possível ver como a pontuação OOM do processo remoto mudou em relação ao processo da interface:
SELECT ts, p.name, value AS oom_score_adj
FROM counter c
JOIN process_counter_track t ON c.track_id = t.id
JOIN process p USING (upid)
WHERE p.name LIKE 'com.android.memorylab%'
AND t.name = 'oom_score_adj'
ORDER BY ts;
3. Identificar eventos de vinculação
Para saber exatamente quando uma dependência de vinculação foi estabelecida e qual processo a iniciou, use esta consulta:
SELECT
s.ts,
p.name AS process_name,
t.name AS thread_name,
s.name AS slice_name
FROM slice s
JOIN thread_track tt ON s.track_id = tt.id
JOIN thread t USING (utid)
JOIN process p USING (upid)
WHERE s.name LIKE 'bindService:{com.android.memorylab%';
Vinculações de sistema para app
O próprio sistema Android geralmente se vincula a serviços em apps de terceiros para fornecer funcionalidades principais. Muitas vezes, o objetivo dessas vinculações é a redução da latência. Ao manter um processo ativo e na memória, o sistema evita o custo extra de uma "inicialização a frio" (carregar o APK, inicializar o tempo de execução e criar o objeto Application) quando ocorre uma interação do usuário crítica. Outras vinculações existem para evitar inicializações a frio frequentes em apps que precisam processar fluxos de eventos em segundo plano.
Confira alguns exemplos reais que você pode observar em um dispositivo comum:
VoiceInteractor
Os usuários esperam que um assistente digital esteja incorporado ao SO do smartphone, que possa ser ativado instantaneamente com uma palavra-chave falada ou um gesto rápido e que a interação seja tranquila e integrada.
Quando um gatilho do assistente é acionado (como a palavra-chave "Ok Google" em smartphones Google Pixel), o assistente digital precisa responder instantaneamente. Para garantir isso, o
system_server mantém uma vinculação permanente ao serviço de interação por voz selecionado pelo usuário.

Se você verificar os estados do processo (por exemplo, usando dumpsys activity processes), poderá encontrar um processo como com.google.android.googlequicksearchbox:interactor no estado BFGS (serviço de primeiro plano vinculado), mantido ativo por uma vinculação de system_server (UID 1000).
NotificationListenerService
Para algumas vinculações do sistema com o app, a meta não é a latência, mas sim evitar
inicializações a frio frequentes.
NotificationListenerService, um serviço que recebe chamadas do sistema quando novas notificações são postadas ou removidas, é um ótimo exemplo. Um usuário comum de smartphone pode receber centenas
de notificações ao longo do dia. Se o sistema desvincular um listener de
notificações, o processo desse app provavelmente entrará no estado em cache e poderá ser
encerrado pelo LMK.
Quando a próxima notificação chegar, possivelmente segundos depois, o sistema será forçado a iniciar a frio o processo do app novamente apenas para entregar o evento. Esse ciclo constante de encerramento e inicialização a frio consumiria muito mais CPU e bateria do que simplesmente manter o processo vinculado e ativo em segundo plano.
A tela "-1" do iniciador (feed de notícias)
Os apps de tela de início modernos geralmente combinam a funcionalidade de navegação principal (ícones e widgets da tela inicial) com um feed de notícias disponível em uma das telas de início e integrado perfeitamente à UX da tela de início. O feed de notícias pode ser fornecido por outro app. Por exemplo, no Google Pixel, o Launcher se integra a um feed fornecido pelo app Google.
Ao deslizar para a esquerda na tela inicial para ver o feed de notícias, a transição precisa ser suave. O iniciador faz isso vinculando-se a uma interface de serviço no app que fornece o feed de notícias e mantendo essa vinculação ativa enquanto o iniciador estiver ativo. Assim, o conteúdo do feed fica renderizado e pronto na memória, mesmo quando você não está olhando para ele.
Outros exemplos comuns
- Tela de início (HOME_APP_ADJ): o app de tela de início (Home) tem um slot especial na lista de prioridade. Embora nem sempre esteja vinculado a um serviço, ele recebe o valor
HOME_APP_ADJ(normalmente 600). O sistema prefere manter o iniciador ativo, porque o usuário volta a ele com frequência. Na verdade, o sistema prefere encerrar o app usado anteriormente (PREV_APP_ADJ = 700) do que o iniciador, porque isso resultaria em uma experiência do usuário lenta ao sair de qualquer app, já que ele precisaria esperar a inicialização a frio do iniciador. - Editor de método de entrada (IME): quando você digita, o sistema se vincula ao app de teclado escolhido (por exemplo, Gboard). Isso mantém o processo do teclado em um estado elevado, mesmo que ele seja ocultado temporariamente. Isso garante que o teclado possa reaparecer instantaneamente quando você tocar em outro campo de texto.
- Pagamentos por aproximação: quando você aproxima o smartphone para pagar, o sistema se vincula ao serviço de pagamento por aproximação (por exemplo, a Carteira do Google). Essas transações geralmente têm requisitos estritos de tempo real do terminal do comerciante. Se o app de pagamento precisar de uma inicialização a frio, a transação poderá expirar e falhar.
Compensações e o declínio de performance
Embora as vinculações sejam necessárias para o desempenho e a correção, elas têm um custo para a integridade da memória do sistema.
- Flexibilidade reduzida: todo processo vinculado é um processo que o LMK não pode encerrar facilmente. Isso reduz a "margem" de processos em cache que o sistema pode usar para liberar memória sob pressão.
- Agravamento do declínio de desempenho: se muitos processos estiverem vinculados, o sistema poderá ficar com quase nenhum processo em segundo plano que possa ser encerrado. Quando a pressão de memória aumenta, o sistema "cai do penhasco de desempenho" muito mais rápido, já que é forçado a encerrar processos mais importantes ou a usar o cache de página.
Antipadrões comuns de vinculação de serviço
Como as vinculações de serviço elevam diretamente oom_score_adj, erros sutis de ciclo de vida na forma como você adquire ou estrutura vinculações podem fixar grandes quantidades de memória em estados privilegiados (BTOP, BFGS ou PERC) por horas. Fique atento
a estes antipadrões comuns ao projetar ou auditar serviços vinculados.
unbindService() esquecidos em clientes de longa duração
A vinculação a um serviço de um singleton Application, um gerenciador em segundo plano ou
um Activity que chama bindService() em onStart() sem um
unbindService() correspondente em onStop() vaza o ServiceConnection.
Enquanto essa vinculação permanecer ativa, o processo de destino vai herdar a
prioridade elevada do cliente. Se o cliente for um componente persistente do sistema ou um aplicativo em primeiro plano, o processo de serviço vinculado vai ficar fixado em BFGS ou BTOP indefinidamente (aparecendo perto de 100% em procstats), impedindo que o LMK recupere a memória mesmo quando o serviço estiver completamente inativo.
Solução: limite as vinculações ao ciclo de vida do componente que
precisa delas ou implemente um tempo limite de inatividade que chame unbindService() após um
período de inatividade. Evite desvincular e revincular em cada chamada de RPC individual, o que causa thrashing de processo e sobrecarga repetida de configuração do Binder. Em vez disso, coalesça bursts de trabalho por trás de um timer de inatividade curto (por exemplo, de 5 a 30 segundos).
Colocar um serviço vinculado com uma interface de uso intensivo de memória
Por padrão, todos os componentes em um APK são executados no mesmo processo. Se o app
expuser um serviço vinculado leve (como um NotificationListenerService, um
provedor de widget ou um serviço de plug-in ao qual o sistema ou o iniciador se vincula) no
mesmo processo do seu Activity principal, todo o processo vai herdar o
estado elevado do serviço (BFGS ou PERC, geralmente oom_score_adj de 200 ou
menos).
Quando o usuário abre a interface do app, o processo aloca grandes hierarquias de visualização, bitmaps decodificados e buffers gráficos. Quando o usuário sai da tela, o processo não cai para CACHED (oom_score_adj de 900 ou mais) porque a vinculação de serviço ativa mantém o processo elevado. Isso causa dois problemas
compostos:
- Nenhuma compactação de memória em segundo plano: o
CachedAppOptimizerdo sistema compacta processos somente depois que eles entram no estadoCACHED. - Nenhum corte de memória LRU em cache ou recuperação de LMK: o sistema não
envia callbacks de corte em segundo plano vinculados à lista LRU em cache
(
TRIM_MEMORY_BACKGROUNDe superior) enquanto uma vinculação de serviço mantém o processo em um estado elevado. Se o app não liberar explicitamente os recursos de UI emTRIM_MEMORY_UI_HIDDENouActivity.onStop(), as alocações de UI de pico vão permanecer fixadas na RAM em uma pontuação OOM privilegiada em que o LMK não pode recuperá-las facilmente.
Solução: remova explicitamente os caches da interface, os bitmaps decodificados e as referências de visualização quando a interface deixar de ficar visível, usando Activity.onStop(), ComponentCallbacks2.onTrimMemory(TRIM_MEMORY_UI_HIDDEN), Application.ActivityLifecycleCallbacks ou ProcessLifecycleOwner. Como alternativa, mova o
serviço sempre vinculado para um processo separado e leve usando o
atributo de manifesto android:process para que o sistema possa mover o processo principal da interface
para o estado CACHED e compactar ou recuperar a memória de forma independente.
Omitir flags de dispensa de prioridade
Chamar bindService() apenas com BIND_AUTO_CREATE transfere todo o agendamento e a prioridade de memória do autor da chamada para o serviço de destino. Quando um app em
primeiro plano se vincula a um serviço de análise, geração de registros ou pré-busca em segundo plano usando apenas
BIND_AUTO_CREATE, ele promove involuntariamente esse worker em segundo plano para
BTOP.
Solução: ao vincular a serviços auxiliares ou de melhor esforço que não precisam do mesmo nível de proteção da interface do usuário em primeiro plano, combine BIND_AUTO_CREATE com BIND_WAIVE_PRIORITY, BIND_NOT_FOREGROUND ou BIND_NOT_PERCEPTIBLE para que o sistema ainda possa gerenciar o processo de destino na lista LRU em cache.
← Região administrativa | ↑ Para cima | Em todo o sistema →