Ontdek Android-processen

Een paar weken geleden was ik bezig met het oplossen van een bug in Android Studio en kwam ik de “android:process”-tag tegen. (Ik werk bij Google in het Android Studio-team.) Ik wist dat je met deze tag het proces kon opgeven waarop het Android-component zal draaien. Maar veel van de details en redeneringen achter Android processen waren mij onbekend. Dus ik las het op en schreef dit artikel om te delen wat ik leerde.

Zoals altijd, ik ben blij om te worden gecorrigeerd op alles wat ik ben verkeerd geïnformeerd over.

Een overzicht op Android Processen

Android is gebaseerd op Linux, dus “het Android-systeem begint een nieuw Linux-proces voor de toepassing met een enkele thread van uitvoering. Standaard draaien alle componenten van dezelfde applicatie in hetzelfde proces en dezelfde thread (de “main” thread genoemd).” (uit: Process and Threads Overview)

Generaal is de “main” thread ook de “UI” thread of de “event” thread, aangezien elke UI wijziging of event afhandeling op deze thread plaatsvindt. (uitzondering: 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̵.̵ Ik had het mis, het is alleen mogelijk voor systeem apps om verschillende MainThread en UIThread te hebben: “De build tools behandelen de @MainThread en @UiThread annotaties als uitwisselbaar, dus je kunt @UiThread methodes aanroepen vanuit @MainThread methodes, en vice versa. Het is echter mogelijk dat een UI thread verschilt van de hoofdthread in het geval van systeem-apps met meerdere weergaven op verschillende threads.”)

Het hoofdproces (en de hoofdthread die het start) draait standaard met een procesnaam die hetzelfde is als applicationId van de applicatie (aangegeven in de build.gradle van uw app). Dus als je een standaard project zou maken met Android Studio, zou je een Android app krijgen die zal draaien op thread: com.example.<username>.myapplication en het bijpassende standaard pakket voor je code.

Wat de “android:process” tag doet

Standaard zal een Android app slechts een enkel proces hebben. Alle componenten draaien op hetzelfde proces. Bij het declareren van nieuwe componenten in het manifest van uw applicatie, kunt u de “android:process” tag gebruiken om een nieuw proces voor deze component te declareren. Zoals dit:

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

In de bovenstaande snippet declareer ik een SettingActivity die zal draaien op het lokale com.example.kelvinma.myapplication:setting proces. (Meer over lokaal vs globaal later in dit artikel)

De “android:process” tag kan worden toegepast op de 4 android componenten:

  • Activity
  • Service
  • Receiver
  • Provider

en ook op de Application tag. Wanneer toegepast op de Application tag, erven alle componenten van de applicatie ook de android:process tenzij overridden door hun eigen android:process tag.

Ik weet niet zeker wat de use case is voor het gebruik van deze tag op uw applicatiedeclaratie wanneer u in plaats daarvan gewoon uw applicationId kunt wijzigen. Als u weet van een, vertel het me.

Een kort visueel voorbeeld

Om een multi-proces app te illustreren, stel ik start de standaard activiteit op mijn Pomodoro applicatie dan met behulp van de snippet hierboven, ik verander mijn SettingsActivity te draaien op een ander proces. Dan na het starten van mijn app en het starten van de SettingsActivity, zal mijn applicatie 2 processen hebben:

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

Alle componenten draaien echter impliciet op het standaard proces, tenzij anders gespecificeerd door de process tag. Dus als je android:process=":setting" toevoegt aan je standaard activiteit en dan een andere activiteit start, zal je app 2 processen hebben:

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

Omdat de gestarte activiteit zal starten op het standaard proces omdat het geen proces tag heeft ingesteld.

Wanneer maak ik mijn app multi-proces?

Er zijn 2 redenen die ik ken om een multi-proces app te maken:

  1. Uw app heeft afzonderlijke acties die onafhankelijk van elkaar moeten worden uitgevoerd, het meest voorkomende voorbeeld is een app voor het afspelen van muziek, waarbij het standaard proces de gebruikersinterface afhandelt en een ander proces voor het afspelen van muziek.
  2. Uw app heeft te kampen met geheugenbeperkingen. Android beperkt het RAM-gebruik op een per proces basis. Dus u kunt de totale RAM-limiet van uw app verhogen door meerdere processen uit te voeren. Maar omdat processen geen geheugen delen, kunt u geen Singleton’s delen tussen processen.

Local vs Global process

Het type proces is afhankelijk van de waarde die u invoert in de process tag. Als je begint met een dubbele punt (“:”) dan is het een lokaal proces dat alleen voor de applicatie bestemd is (de volledige procesnaam zou zijn applicationId:processName). Als je begint met een kleine letter dan is het een globaal proces.

Een globaal proces kan worden gedeeld tussen applicaties. Vaak zal een bibliotheek op een globaal proces draaien zodat meerdere applicaties het proces kunnen delen om geheugengebruik te verminderen.

android:process quiz

Laten we eindigen met een paar scenario’s, kijken of je het antwoord kunt voorspellen.

Q: Wat gebeurt er als je een globaal proces gebruikt om je proces in te stellen op je pakket-id? android:process="com.example.kelvinhanma.pomodoro"

A: Je proces blijft ongewijzigd en dit is toegestaan.

Q: Wat gebeurt er als je een globaal proces gebruikt om je proces in te stellen op het pakket van een andere app? Stel dat ik een com.example.kelvinhanma.pomodoro op mijn apparaat heb draaien. Ik stel het globale proces van een andere app in op dezelfde naam en implementeer het.

Ik zou eindigen met 2 processen met dezelfde naam!

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

Maar dat is prima. Procesnamen hoeven niet uniek te zijn. Merk op dat de gebruikers verschillend zijn (u0_a181, u0_a179) en dat de proces ids uniek zijn.

Hoop dat je genoten hebt van het artikel en iets geleerd hebt. Voel je vrij om me te laten weten als er iets niet klopt!