In Android 9 und niedriger ist ein Thread in libsuspend für die Initiierung des Systemstopps verantwortlich. Android 10 führt eine entsprechende Funktion in einem SystemSuspend-HIDL-Dienst ein.
Dieser Dienst befindet sich im System-Image und wird von der Android-Plattform bereitgestellt.
Die Logik aus libsuspend
bleibt weitgehend unverändert, mit der Ausnahme, dass jeder Userspace-Prozess, der das System-Suspend blockiert, mit SystemSuspend kommunizieren muss.
libsuspend und libpower
In Android 10 wird libsuspend
durch den SystemSuspend-Dienst ersetzt. libpower
wurde neu implementiert, um statt /sys/power/wake[un]lock
den SystemSuspend-Dienst zu verwenden, ohne die C-API zu ändern.
Dieser Pseudocode zeigt, wie acquire_wake_lock
und release_wake_lock
implementiert werden.
static std::unordered_map<std::string, sp<IWakeLock>> gWakeLockMap;
int acquire_wake_lock(int, const char* id) {
...
if (!gWakeLockMap[id]) {
gWakeLockMap[id] = suspendService->acquireWakeLock(WakeLockType::PARTIAL, id);
}
...
return 0;
}
int release_wake_lock(const char* id) {
...
if (gWakeLockMap[id]) {
auto ret = gWakeLockMap[id]->release();
gWakeLockMap[id].clear();
return 0;
}
...
return -1;
}
Ausführungsthreads
Der SystemSuspend-Dienst überwacht die Anzahl der Wakelocks, die mit einem Suspend-Zähler ausgegeben werden. Es gibt zwei Ausführungsthreads:
- Der main-Thread beantwortet Binder-Aufrufe.
- Der Thread suspend steuert die Systemaussetzung.
Hauptthread
Der Hauptthread beantwortet Anfragen von Clients, um neue Wakelocks zuzuweisen, wodurch der Sperrzähler erhöht/dekrementiert wird.
Unterhaltung pausieren
Der Sperren-Thread führt in einer Schleife Folgendes aus:
- Aus
/sys/power/wakeup_count
lesen - Erwerben Sie den Mutex. So wird sichergestellt, dass der Suspend-Thread den Suspend-Zähler nicht berührt, während der Hauptthread versucht, ihn zu erhöhen oder zu verringern. Der main-Thread wird beim Ausstellen oder Entfernen von Aufwecksperren blockiert, wenn der Aussetzungszähler null erreicht hat und der suspend-Thread ausgeführt werden soll.
- Warten Sie, bis der Zähler null ist.
- Schreibe den aus
/sys/power /wakeup_count
(Schritt 1) gelesenen Wert in diese Datei. Wenn das Schreiben fehlschlägt, kehren Sie zum Anfang der Schleife zurück. - Starten Sie den System-Suspend, indem Sie
mem
in/sys/power/state
schreiben. - Lassen Sie den Mutex los.
Wenn eine Anfrage für eine Wakelock erfolgreich zurückgegeben wird, wird der Suspend-Thread blockiert.
SystemAnhalten-API
Die SystemSuspend API besteht aus zwei Schnittstellen. Die HIDL-Schnittstelle wird von nativen Prozessen verwendet, um Wakelocks zu erhalten, die AIDL-Schnittstelle wird für die Kommunikation zwischen SystemServer und SystemSuspend verwendet.
ISystemSuspend HIDL-Schnittstelle
enum WakeLockType : uint32_t {
PARTIAL,
FULL
};
interface IWakeLock {
oneway release();
};
interface ISystemSuspend {
acquireWakeLock(WakeLockType type, string debugName)
generates (IWakeLock lock);
};
Jeder Client, der eine Wakelock anfordert, erhält eine eindeutige IWakeLock
-Instanz. Das unterscheidet sich von /sys/power/wake_lock
, bei dem mehrere Clients die Wakelock unter demselben Namen verwenden können. Wenn ein Client, der eine IWakeLock
-Instanz hält, beendet wird, werden die Ressourcen durch den Binder-Treiber und den SystemSuspend-Dienst bereinigt.
AIDL-Schnittstelle „ISuspendControlService“
ISuspendControlService darf nur vom SystemServer verwendet werden.
interface ISuspendCallback {
void notifyWakeup(boolean success);
}
interface ISuspendControlService {
boolean enableAutosuspend();
boolean registerCallback(ISuspendCallback callback);
boolean forceSuspend();
}
Die Nutzung von Android HIDL bietet folgende Vorteile:
- Wenn ein Prozess, der das Aussetzen blockiert, beendet wird, kann SystemSuspend benachrichtigt werden.
- Dem Thread, der für die Systemaussetzung verantwortlich ist, kann ein Rückruf zugewiesen werden.