Exploring Android Processes

Vor ein paar Wochen war ich dabei, einen Fehler in Android Studio zu beheben und stieß dabei auf das Tag „android:process“. (Ich arbeite bei Google im Android-Studio-Team.) Ich wusste, dass man mit dem Tag den Prozess angeben kann, auf dem die Android-Komponente ausgeführt wird. Viele der Details und Überlegungen, die hinter Android-Prozessen stecken, waren mir jedoch unbekannt. Also habe ich nachgelesen und diesen Artikel geschrieben, um mitzuteilen, was ich gelernt habe.

Wie immer freue ich mich, wenn ich korrigiert werde, wenn ich falsch informiert bin.

Ein Überblick über Android-Prozesse

Android basiert auf Linux, daher „startet das Android-System einen neuen Linux-Prozess für die Anwendung mit einem einzigen Ausführungsstrang. Standardmäßig laufen alle Komponenten einer Anwendung in demselben Prozess und Thread (dem sogenannten „Haupt-Thread“).“ (aus: Process and Threads Overview)

Generell ist der „Haupt“-Thread auch der „UI“-Thread oder der „Event“-Thread, da jede UI-Änderung oder Ereignisbehandlung in diesem Thread stattfindet. (Ausnahme: 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̵o̵n̵s.̵ Ich habe mich geirrt, es ist nur bei System-Apps möglich, einen unterschiedlichen MainThread und UIThread zu haben: „Die Build-Tools behandeln die @MainThread– und @UiThread-Annotationen als austauschbar, so dass man @UiThread-Methoden von @MainThread-Methoden aufrufen kann und umgekehrt. Es ist jedoch möglich, dass sich ein UI-Thread vom Hauptthread unterscheidet, wenn es sich um Systemanwendungen mit mehreren Ansichten auf verschiedenen Threads handelt.“

Standardmäßig läuft der Hauptprozess (und der von ihm gestartete Hauptthread) mit einem Prozessnamen, der mit der applicationId der Anwendung übereinstimmt (die in der build.gradle Ihrer Anwendung deklariert ist). Wenn Sie also ein Standardprojekt mit Android Studio erstellen, erhalten Sie eine Android-App, die auf dem Thread: com.example.<Benutzername>.myapplication und dem passenden Standardpaket für Ihren Code läuft.

Was das „android:process“ Tag macht

Standardmäßig hat eine Android-App nur einen einzigen Prozess. Alle Komponenten werden auf demselben Prozess ausgeführt. Wenn Sie neue Komponenten im Manifest Ihrer Anwendung deklarieren, können Sie das „android:process“-Tag verwenden, um einen neuen Prozess für diese Komponente zu deklarieren. Etwa so:

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

Im obigen Ausschnitt wird eine SettingActivity deklariert, die auf dem lokalen Prozess com.example.kelvinma.myapplication:setting ausgeführt wird. (mehr zu lokal vs. global später in diesem Artikel)

Das „android:process“ Tag kann auf die 4 Android Komponenten angewendet werden:

  • Activity
  • Service
  • Receiver
  • Provider

und auch auf das Application Tag. Wenn es auf das Application-Tag angewendet wird, erbt jede Komponente der Anwendung auch das android:process, es sei denn, es wird durch ihr eigenes android:process-Tag überschrieben.

Ich bin mir nicht sicher, was der Anwendungsfall für die Verwendung dieses Tags in der Anwendungsdeklaration ist, wenn man stattdessen einfach die applicationId ändern kann. Wenn Sie einen kennen, sagen Sie es mir bitte.

Ein kurzes visuelles Beispiel

Um eine Multiprozess-Anwendung zu veranschaulichen, nehmen wir an, ich starte die Standardaktivität in meiner Pomodoro-Anwendung und ändere dann mit dem obigen Ausschnitt meine SettingsActivity so, dass sie in einem anderen Prozess läuft. Nach dem Starten meiner Anwendung und dem Starten der SettingsActivity hat meine Anwendung dann 2 Prozesse:

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

Allerdings laufen alle Komponenten implizit auf dem Standardprozess, es sei denn, das Prozess-Tag gibt etwas anderes an. Wenn Sie also android:process=":setting" zu Ihrer Standardaktivität hinzufügen und dann eine andere Aktivität starten, wird Ihre Anwendung 2 Prozesse haben:

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

Denn die gestartete Aktivität wird auf dem Standardprozess gestartet, da sie kein Prozess-Tag gesetzt hat.

Wann mache ich meine Anwendung multiprozessfähig?

Es gibt 2 Gründe, die ich kenne, um eine App mit mehreren Prozessen zu erstellen:

  1. Ihre App hat separate Aktionen, die unabhängig voneinander ausgeführt werden müssen, das übliche Beispiel ist eine Musikwiedergabe-App, bei der der Standardprozess die Benutzeroberfläche und ein anderer Prozess die Musikwiedergabe übernimmt.
  2. Ihre App stößt auf Speicherbeschränkungen. Android begrenzt die RAM-Nutzung auf Prozessbasis. Sie können also das Gesamt-RAM-Limit Ihrer App erhöhen, indem Sie mehrere Prozesse ausführen. Da Prozesse jedoch keinen Speicher gemeinsam nutzen, können Sie keine Singletons zwischen Prozessen teilen.

Lokaler vs. Globaler Prozess

Der Typ des Prozesses hängt von dem Wert ab, den Sie in das Prozess-Tag eingeben. Wenn Sie mit einem Doppelpunkt („:“) beginnen, handelt es sich um einen lokalen Prozess, der für Ihre Anwendung privat ist (der vollständige Prozessname wäre applicationId:processName). Wenn Sie mit einem Kleinbuchstaben beginnen, handelt es sich um einen globalen Prozess.

Ein globaler Prozess kann von verschiedenen Anwendungen gemeinsam genutzt werden. Oft läuft eine Bibliothek auf einem globalen Prozess, so dass mehrere Anwendungen den Prozess teilen können, um den Speicherverbrauch zu reduzieren.

android:process quiz

Lassen Sie uns mit ein paar Szenarien enden, sehen Sie, ob Sie die Antwort vorhersagen können.

Q: Was passiert, wenn Sie einen globalen Prozess verwenden, um Ihren Prozess auf Ihre Paket-ID zu setzen? android:process="com.example.kelvinhanma.pomodoro"

A: Ihr Prozess bleibt unverändert und das ist erlaubt. Obwohl es eine sinnlose und dumme Sache ist.

Q: Was ist, wenn man es benutzt, um seinen Prozess auf das Paket einer anderen Anwendung zu setzen? Angenommen, ich habe eine com.example.kelvinhanma.pomodoro auf meinem Gerät laufen. Ich setze den globalen Prozess einer anderen Anwendung auf denselben Namen und setze ihn ein.

Ich hätte dann 2 Prozesse mit demselben Namen!

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

Aber das ist in Ordnung. Prozessnamen müssen nicht eindeutig sein. Beachten Sie, dass die Benutzer unterschiedlich sind (u0_a181, u0_a179) und die Prozess-IDs eindeutig sind.

Ich hoffe, der Artikel hat Ihnen gefallen und Sie haben etwas gelernt. Bitte lassen Sie mich wissen, wenn etwas falsch ist!