In Android 9 und niedriger gibt es einen Thread in libsuspend
, der für das Initiieren des System-Suspend-Modus verantwortlich ist. In Android 10
wird eine entsprechende Funktion in einem SystemSuspend HIDL-Dienst eingeführt.
Dieser Dienst befindet sich im Systemimage und wird von der Android-Plattform bereitgestellt.
Die Logik von libsuspend bleibt weitgehend gleich. Allerdings muss jeder Userspace
Prozess, der den System-Suspend-Modus blockiert, mit SystemSuspend kommunizieren.
libsuspend und libpower
In Android 10 ersetzt der SystemSuspend-Dienst
libsuspend. libpower wurde neu implementiert, um den SystemSuspend-Dienst anstelle von /sys/power/wake[un]lock 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 verfolgt die Anzahl der mit einem Suspend-Zähler ausgegebenen Wake Locks. Er hat zwei Ausführungsthreads:
- Der Hauptthread beantwortet Binder-Aufrufe.
- Der Suspend-Thread steuert den System-Suspend-Modus.
Hauptthread
Der Hauptthread beantwortet Anfragen von Clients, um neue Wake Locks zuzuweisen, und erhöht oder verringert den Suspend-Zähler.
Suspend-Thread
Der Suspend-Thread führt die folgenden Schritte in einer Schleife aus:
- Aus
/sys/power/wakeup_countlesen. - Mutex abrufen. Dadurch 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 Hauptthread wird beim Ausgeben oder Entfernen von Wake Locks blockiert, wenn der Suspend-Zähler null erreicht hat und der Suspend-Thread versucht, ausgeführt zu werden.
- Warten, bis der Zähler null ist.
- Den aus
/sys/power /wakeup_countgelesenen Wert (aus Schritt 1) in diese Datei schreiben. Wenn der Schreibvorgang fehlschlägt, zum Anfang der Schleife zurückkehren. - Den System-Suspend-Modus starten, indem
memin/sys/power/stategeschrieben wird. - Mutex freigeben.
Wenn eine Anfrage für einen Wakelock erfolgreich zurückgegeben wird, wird der Suspend-Thread blockiert.
SystemSuspend API
Die SystemSuspend API besteht aus zwei Schnittstellen. Die HIDL-Schnittstelle wird von nativen Prozessen verwendet, um Wake Locks abzurufen, und 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 ein Wakelock anfordert, erhält eine eindeutige
IWakeLock Instanz. Dies unterscheidet sich von
/sys/power/wake_lock, wodurch mehrere
Clients das Wakelock unter demselben Namen verwenden können. Wenn ein Client, der eine
IWakeLock Instanz enthält, beendet wird, wird sie vom Binder-Treiber und
SystemSuspend-Dienst bereinigt.
ISuspendControlService AIDL-Schnittstelle
ISuspendControlService ist nur für die Verwendung durch SystemServer vorgesehen.
interface ISuspendCallback {
void notifyWakeup(boolean success);
}
interface ISuspendControlService {
boolean enableAutosuspend();
boolean registerCallback(ISuspendCallback callback);
boolean forceSuspend();
}
Die Verwendung von Android HIDL bietet die folgenden Vorteile:
- Wenn ein Prozess, der den Suspend-Modus blockiert, beendet wird, kann SystemSuspend benachrichtigt werden.
- Der Thread, der für den System-Suspend-Modus verantwortlich ist, kann einen Callback erhalten.