Explorarea proceselor Android

Cu câteva săptămâni în urmă am reparat o eroare în Android Studio și am dat peste tag-ul „android:process”. (Lucrez la Google în echipa Android Studio.) Știam că tagul vă permite să specificați procesul pe care va rula componenta android. Cu toate acestea, multe dintre detaliile mai fine și raționamentele din spatele proceselor Android îmi erau necunoscute. Așa că m-am documentat și am scris acest articol pentru a împărtăși ceea ce am învățat.

Ca întotdeauna, sunt bucuros să fiu corectat cu privire la orice lucru despre care sunt dezinformat.

O privire de ansamblu asupra proceselor Android

Android se bazează pe linux, astfel încât „sistemul Android începe un nou proces Linux pentru aplicație cu un singur fir de execuție. În mod implicit, toate componentele aceleiași aplicații rulează în același proces și fir de execuție (numit fir „principal”)”. (din: Process and Threads Overview)

În general, firul „principal” este, de asemenea, firul „UI” sau firul „evenimentelor”, deoarece orice modificare a interfeței de interfață sau gestionarea evenimentelor are loc pe acest fir. (excepție: y̵o̵u̵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-am înșelat, este posibil doar ca aplicațiile de sistem să aibă MainThread și UIThread diferite: „Instrumentele de construcție tratează adnotările @MainThread și @UiThread ca fiind interschimbabile, astfel încât puteți apela metodele @UiThread din metodele @MainThread și invers. Cu toate acestea, este posibil ca un fir UI să fie diferit de firul principal în cazul aplicațiilor de sistem cu mai multe vizualizări pe fire diferite.”)

În mod implicit, procesul principal (și firul principal pe care îl pornește) rulează cu un nume de proces care este același cu applicationId al aplicației (declarat în fișierul build.gradle al aplicației dumneavoastră). Astfel, dacă ar fi să creați un proiect implicit cu Android Studio, veți obține o aplicație Android care va rula pe firul de execuție: com.example.<username>.myapplication și pachetul implicit corespunzător pentru codul dumneavoastră.

Ce face tag-ul „android:process”

În mod implicit, o aplicație Android va avea doar un singur proces. Toate componentele vor rula pe același proces. Atunci când declarați noi componente în manifestul aplicației dumneavoastră, puteți utiliza tag-ul „android:process” pentru a declara un nou proces pentru această componentă. Astfel:

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

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

În fragmentul de mai sus declar o SettingActivity care va rula pe procesul local com.example.kelvinma.myapplication:setting. (mai multe despre local vs global mai târziu în acest articol)

Eticheta „android:process” poate fi aplicată pe cele 4 componente android:

  • Activity
  • Service
  • Receiver
  • Provider

și, de asemenea, pe eticheta Application. Atunci când se aplică pe eticheta Application, orice componentă a aplicației moștenește, de asemenea, android:process, cu excepția cazului în care este suprascrisă de propria lor etichetă android:process.

Nu sunt sigur care este cazul de utilizare pentru a folosi această etichetă pe declarația aplicației, atunci când puteți schimba pur și simplu applicationId în schimb. Dacă știți unul, vă rog să-mi spuneți.

Un scurt exemplu vizual

Pentru a ilustra o aplicație multiproces, să presupunem că pornesc activitatea implicită pe aplicația mea Pomodoro, apoi, folosind fragmentul de mai sus, îmi schimb SettingsActivity pentru a rula pe un alt proces. Apoi, după pornirea aplicației mele și după pornirea SettingsActivity, aplicația mea va avea 2 procese:

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

Cu toate acestea, toate componentele rulează implicit pe procesul implicit, cu excepția cazului în care se specifică altfel prin eticheta process. Deci, dacă adăugați android:process=":setting"la activitatea implicită și apoi porniți o altă activitate, aplicația dvs. va avea 2 procese:

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

Pentru că activitatea pornită va porni pe procesul implicit, deoarece nu are setată o etichetă process.

Când îmi fac aplicația multiproces?

Există 2 motive pe care le cunosc pentru a crea o aplicație multiproces:

  1. Aplicația dvs. are acțiuni separate care trebuie să fie rulate independent, exemplul obișnuit este o aplicație de redare a muzicii ar avea procesul implicit care se ocupă de UI și un alt proces care să se ocupe de redarea muzicii.
  2. Aplicația dvs. se lovește de constrângeri de memorie. Android limitează utilizarea RAM în funcție de fiecare proces în parte. Astfel, puteți crește limita totală de RAM a aplicației dvs. prin rularea mai multor procese. Cu toate acestea, deoarece procesele nu partajează memoria, nu puteți partaja Singleton-uri între procese.

Proces local vs. proces global

Tipul procesului depinde de valoarea pe care o introduceți în tag-ul process. Dacă începeți cu două puncte („:”), atunci procesul este unul local, care este privat pentru aplicația dumneavoastră (numele complet al procesului ar fi applicationId:processName). Dacă începeți cu o literă minusculă, atunci este un proces global.

Un proces global poate fi partajat între aplicații. Adesea, o bibliotecă va rula pe un proces global, astfel încât mai multe aplicații pot partaja procesul pentru a reduce utilizarea memoriei.

android:process quiz

Să încheiem cu câteva scenarii, vedeți dacă puteți prezice răspunsul.

Întrebare: Ce se întâmplă dacă folosiți un proces global pentru a seta procesul la ID-ul pachetului dvs. android:process="com.example.kelvinhanma.pomodoro"

A: Procesul dvs. rămâne neschimbat și acest lucru este permis. Deși este un lucru inutil și prostesc de făcut.

Întrebare: Ce se întâmplă dacă îl folosiți pentru a vă seta procesul la pachetul altei aplicații? Să presupunem că am un com.example.kelvinhanma.pomodoro care rulează pe dispozitivul meu. Setez procesul global al unei alte aplicații cu același nume și îl implementez.

Am ajunge să am 2 procese cu același nume!

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

Dar asta este în regulă. Numele proceselor nu trebuie să fie unice. Observați că utilizatorii sunt diferiți (u0_a181, u0_a179) și ID-urile proceselor sunt unice.

Sperăm că v-a plăcut articolul și ați învățat ceva. Nu ezitați să mă anunțați dacă ceva este incorect!

.