Zkoumání procesů Androidu

Před několika týdny jsem opravoval chybu v Android Studiu a narazil jsem na značku „android:process“. (Pracuji ve společnosti Google v týmu Android Studio.) Věděl jsem, že tento tag umožňuje určit proces, na kterém bude spuštěna komponenta Android. Mnoho jemnějších detailů a zdůvodnění procesů Androidu mi však bylo neznámých. Tak jsem si o tom něco přečetl a napsal tento článek, abych se podělil o to, co jsem se dozvěděl.

Jako vždy budu rád, když mě někdo opraví v čemkoli, o čem jsem špatně informován.

Přehled o procesech Androidu

Android je založen na Linuxu, takže „systém Android spustí nový linuxový proces pro aplikaci s jedním vláknem provádění. Ve výchozím nastavení jsou všechny součásti téže aplikace spuštěny ve stejném procesu a vlákně (nazývaném „hlavní“ vlákno).“. (z: Přehled procesů a vláken)

Obvykle je „hlavní“ vlákno také vláknem „uživatelského rozhraní“ nebo vláknem „událostí“, protože veškeré úpravy uživatelského rozhraní nebo zpracování událostí probíhá v tomto vlákně. (Výjimka: 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̵i̵o̵n̵s̵.̵ Mýlil jsem se, pouze systémové aplikace mohou mít různé MainThread a UIThread: „Nástroje pro sestavování považují anotace @MainThread a @UiThread za zaměnitelné, takže můžete volat metody @UiThread z metod @MainThread a naopak. Je však možné, aby se vlákno uživatelského rozhraní lišilo od hlavního vlákna v případě systémových aplikací s více zobrazeními v různých vláknech.“)

Ve výchozím nastavení běží hlavní proces (a hlavní vlákno, které spouští) s názvem procesu, který je stejný jako applicationId aplikace (deklarovaný v souboru build.gradle vaší aplikace). Pokud byste tedy vytvořili výchozí projekt pomocí aplikace Android Studio, získali byste aplikaci Android, která poběží na vlákně: com.example.<username>.myapplication a odpovídajícím výchozím balíčku pro váš kód.

Co dělá značka „android:process“

Ve výchozím nastavení bude mít aplikace Android pouze jeden proces. Všechny komponenty budou spuštěny na stejném procesu. Při deklarování nových komponent v manifestu aplikace můžete pomocí značky „android:process“ deklarovat nový proces pro tuto komponentu. Například takto:

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

V úryvku výše deklaruji SettingActivity, která poběží na místním procesu com.example.kelvinma.myapplication:setting. (více o lokálním vs. globálním později v tomto článku)

Tag „android:process“ lze použít na 4 komponenty android:

  • Activity
  • Service
  • Receiver
  • Provider

a také na tag Application. Při použití na tag Application zdědí všechny komponenty aplikace také android:process, pokud nejsou přepsány vlastním tagem android:process.

Nejsem si jistý, jaký je případ použití tohoto tagu na deklaraci aplikace, když místo toho stačí změnit applicationId. Pokud o nějakém víte, řekněte mi ho, prosím.

Krátký vizuální příklad

Pro ilustraci víceprocesové aplikace předpokládejme, že spustím výchozí aktivitu na své aplikaci Pomodoro a pak pomocí výše uvedeného úryvku změním svou aktivitu SettingsActivity tak, aby běžela na jiném procesu. Pak po spuštění mé aplikace a spuštění SettingsActivity bude mít moje aplikace 2 procesy:

$ ./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

Všechny komponenty však implicitně běží na výchozím procesu, pokud není značkou process určeno jinak. Pokud tedy do výchozí aktivity přidáte android:process=":setting" a poté spustíte jinou aktivitu, bude mít vaše aplikace 2 procesy:

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

Protože spuštěná aktivita se spustí na výchozím procesu, protože nemá nastavenou značku procesu.

Kdy mám ze své aplikace udělat víceprocesovou?

Vím o dvou důvodech, proč vytvořit víceprocesovou aplikaci:

  1. Vaše aplikace má samostatné činnosti, které je třeba spouštět nezávisle, běžným příkladem je aplikace pro přehrávání hudby, která by měla výchozí proces pro obsluhu uživatelského rozhraní a další proces pro obsluhu přehrávání hudby.
  2. Vaše aplikace naráží na omezení paměti. Systém Android omezuje využití paměti RAM na základě jednotlivých procesů. Celkový limit paměti RAM aplikace tedy můžete zvýšit spuštěním více procesů. Protože však procesy nesdílejí paměť, nemůžete mezi procesy sdílet Singleton.

Lokální vs. globální proces

Typ procesu závisí na hodnotě, kterou zadáte do značky procesu. Pokud začínáte dvojtečkou („:“), pak se jedná o lokální proces, který je soukromý pro vaši aplikaci (celý název procesu by byl applicationId:processName). Pokud začínáte malým písmenem, pak se jedná o globální proces.

Globální proces může být sdílen mezi aplikacemi. Na globálním procesu často běží knihovna, takže jej může sdílet více aplikací, aby se snížila spotřeba paměti.

android:process quiz

Na závěr si řekneme několik scénářů, zda dokážete předpovědět odpověď.

Q: Co se stane, když použijete globální proces a nastavíte svůj proces na id balíčku? android:process="com.example.kelvinhanma.pomodoro"

A: Váš proces zůstane nezměněn a je to povoleno. I když je to nesmyslná a hloupá věc.

Q: Co když ho použijete k nastavení svého procesu na balíček jiné aplikace? Dejme tomu, že mám na svém zařízení spuštěný com.example.kelvinhanma.pomodoro. Nastavím globální proces jiné aplikace na stejný název a nasadím ho.

Skončil bych se dvěma procesy se stejným názvem!

./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

Ale to je v pořádku. Názvy procesů nemusí být jedinečné. Všimněte si, že uživatelé jsou různí (u0_a181, u0_a179) a id procesů jsou jedinečná.

Doufám, že se vám článek líbil a něco jste se dozvěděli. Neváhejte mi dát vědět, pokud je něco špatně!