Explorando Processos Android

A poucas semanas atrás eu estava corrigindo um bug no Android Studio e me deparei com a tag “android:process”. (Eu trabalho no Google na equipe do Android Studio.) Eu sabia que a tag permite que você especifique o processo no qual o componente android será executado. No entanto, muitos dos detalhes e raciocínios por trás dos processos do Android eram desconhecidos para mim. Então eu li sobre ele e escrevi este artigo para compartilhar o que aprendi.

Como sempre, estou feliz em ser corrigido em qualquer coisa sobre a qual estou mal informado.

Uma visão geral dos processos do Android

Android é baseado no linux então “o sistema Android inicia um novo processo Linux para o aplicativo com um único tópico de execução. Por padrão, todos os componentes da mesma aplicação são executados no mesmo processo e thread (chamado thread “principal”)”. (de: Process and Threads Overview)

Generalmente a thread “principal” também é a thread “UI” ou a thread “event”, pois qualquer modificação de UI ou manipulação de eventos ocorre nesta thread. (exceção: y̵o̵u̵ ̵c̵a̵n̵ ̵c̵h̵a̵n̵g̵e̵ ̵t̵h̵i̵s̵ ̵b̵y̵ ̵u̵s̵i̵n̵g̵ ̵T̵h̵r̵e̵a̵d̵ ̵A̵n̵n̵o̵t̵a̵t̵a̵o̵i̵o̵n̵s̵.̵ Eu estava errado, só é possível que os aplicativos do sistema tenham diferentes MainThread e UIThread: “As ferramentas de construção tratam as anotações @MainThread e @UiThread como intercambiáveis, por isso pode chamar métodos @UiThread a partir de métodos @MainThread e vice-versa. No entanto, é possível que uma thread UI seja diferente da thread principal no caso de aplicações de sistema com múltiplas vistas em threads diferentes”)

Por padrão o processo principal (e a thread principal que ele inicia) roda com um nome de processo que é o mesmo que applicationId da aplicação (declarado no build.gradle da sua aplicação). Então se você fosse criar um projeto padrão com o Android Studio, você teria um aplicativo Android que seria executado na thread: com.example.<username>.myapplication e o pacote padrão correspondente para o seu code.

O que a tag “android:process” faz

Por padrão um aplicativo Android só terá um único processo. Todos os componentes serão executados no mesmo processo. Ao declarar novos componentes no manifesto do seu aplicativo, você pode usar a tag “android:process” para declarar um novo processo para este componente. Assim:

<activity
android:name=".SettingsActivity"
android:process=":setting"
android:label="@string/title_activity_settings">
</activity>

No snippet acima eu declaro uma SettingActivity que será executada no processo local com.example.kelvinma.myapplication:setting. (mais sobre local vs global mais tarde neste artigo)

A etiqueta “android:process” pode ser aplicada nos 4 componentes android:

  • Atividade
  • Serviço
  • Receptor
  • Provedor

e também na etiqueta Aplicação. Quando aplicado na tag Application, qualquer componente da aplicação também herda o android:process a menos que seja substituído por seu próprio android:process tag.

Não tenho certeza de qual é o caso de uso desta tag na declaração da sua aplicação quando você pode simplesmente alterar sua aplicaçãoId em seu lugar. Se você conhece algum, por favor me diga.

Um pequeno exemplo visual

Para ilustrar uma aplicação multi-processo, suponha que eu inicie a atividade padrão em minha aplicação Pomodoro e então usando o snippet acima, eu mudei minhas ConfiguraçõesAtividade para rodar em outro processo. Depois de iniciar a minha aplicação e o início da SettingsActivity, a minha aplicação terá 2 processos:

$ ./adb shell ps | grep kelvin
u0_a61 32175 1669 1292180 47600 SyS_epoll_ b738f2b5 S com.example.kelvinhanma.pomodoro
u0_a61 32223 1669 1284796 43736 SyS_epoll_ b738f2b5 S com.example.kelvinhanma.pomodoro:setting

No entanto, todos os componentes são implicitamente executados no processo padrão, a menos que especificado de outra forma pela tag do processo. Então se você adicionar android:process=":setting" à sua atividade padrão e então iniciar outra atividade, sua aplicação terá 2 processos:

com.example.kelvinhanma.pomodoro:setting
com.example.kelvinhanma.pomodoro

Porque a atividade iniciada será iniciada no processo padrão, pois não tem uma tag de processo definida.

Quando eu faço minha aplicação multi-processo?

Existem 2 razões que conheço para criar um aplicativo multi-processo:

  1. Seu aplicativo tem ações separadas que precisam ser executadas independentemente, o exemplo comum é que um aplicativo que toca música teria o processo padrão de manipulação UI e outro processo para manipular a música tocando.
  2. Seu aplicativo está atingindo restrições de memória. O Android limita o uso da RAM por processo. Então você pode aumentar o limite total de RAM do seu aplicativo, executando vários processos. No entanto, como os processos não compartilham memória, você não pode compartilhar Singleton’s entre processos.

Processo Local vs Global

O tipo do processo depende do valor que você digitar na etiqueta do processo. Se você começar com dois pontos (“:”) então o processo é local e privado para sua aplicação (o nome completo do processo seria applicationId:processName). Se você começar com uma letra minúscula, então é um processo global.

Um processo global pode ser compartilhado entre as aplicações. Muitas vezes uma biblioteca será executada em um processo global para que múltiplas aplicações possam compartilhar o processo para reduzir o uso de memória.

android:process quiz

Levemos terminar com alguns cenários, veja se você pode prever a resposta.

Q: O que acontece se você usar um processo global para definir o seu processo para o seu pacote id? android:process="com.example.kelvinhanma.pomodoro"

A: O seu processo permanece inalterado e isto é permitido. Embora seja uma coisa inútil e tola.

Q: E se você usá-lo para configurar seu processo para o pacote de outro aplicativo? Suponha que eu tenha um com.example.kelvinhanma.pomodoro rodando no meu dispositivo. Eu defino o processo global de outro aplicativo com o mesmo nome e o implanto.

Acabaria com 2 processos com o mesmo nome!

./adb shell ps | grep kelvin
u0_a181 28008 630 4324212 66060 SyS_epoll_wait 0 S com.example.kelvinhanma.pomodoro
u0_a179 28287 630 4327384 66200 SyS_epoll_wait 0 S com.example.kelvinhanma.pomodoro

Mas tudo bem. Os nomes dos processos não têm de ser únicos. Note que os usuários são diferentes (u0_a181, u0_a179) e os ids dos processos são únicos.

Espere que você tenha gostado do artigo e tenha aprendido algo. Esteja à vontade para me avisar se algo estiver incorrecto!