SystemSuspend-Dienst

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:

  1. Aus /sys/power/wakeup_count lesen.
  2. 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.
  3. Warten, bis der Zähler null ist.
  4. Den aus /sys/power /wakeup_count gelesenen Wert (aus Schritt 1) in diese Datei schreiben. Wenn der Schreibvorgang fehlschlägt, zum Anfang der Schleife zurückkehren.
  5. Den System-Suspend-Modus starten, indem mem in /sys/power/state geschrieben wird.
  6. Mutex freigeben.

Wenn eine Anfrage für einen Wakelock erfolgreich zurückgegeben wird, wird der Suspend-Thread blockiert.

Abbildung 1. Suspend-Thread-Schleife

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.