SystemSuspend-Dienst

In Android 9 und niedriger gibt es einen Thread in libsuspend, der für das Initiieren des System-Suspend-Vorgangs verantwortlich ist. In Android 10 wird eine entsprechende Funktion in einem SystemSuspend-HIDL-Dienst eingeführt. 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 ersetzt der SystemSuspend-Dienst libsuspend. libpower wurde neu implementiert und verwendet jetzt den SystemSuspend-Dienst anstelle von /sys/power/wake[un]lock, 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. Es gibt zwei Ausführungsstränge:

  • Der Hauptthread beantwortet Binder-Aufrufe.
  • Der suspend-Thread steuert das Anhalten des Systems.

Hauptthread

Der Hauptthread beantwortet Anfragen von Clients zum Zuweisen neuer Wake Locks und zum Erhöhen/Verringern des Suspend-Zählers.

Thread sperren

Der Thread zum Anhalten führt Folgendes in einer Schleife aus:

  1. Aus /sys/power/wakeup_count lesen
  2. Das Mutex wird angefordert. So wird sichergestellt, dass der Thread zum Anhalten den Zähler zum Anhalten nicht berührt, während der Hauptthread versucht, ihn zu inkrementieren oder zu dekrementieren. Der Hauptthread wird blockiert, wenn Wake Locks ausgegeben oder entfernt werden, wenn der Suspend-Zähler null erreicht hat und der Suspend-Thread versucht, ausgeführt zu werden.
  3. Warten Sie, bis der Zähler null erreicht.
  4. Schreiben Sie den aus /sys/power /wakeup_count gelesenen Wert (aus Schritt 1) in diese Datei. Wenn der Schreibvorgang fehlschlägt, kehren Sie zum Anfang der Schleife zurück.
  5. Leiten Sie den System-Suspend ein, indem Sie mem in /sys/power/state schreiben.
  6. Geben Sie den Mutex frei.

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

Abbildung 1: Thread-Schleife anhalten

SystemSuspend API

Die SystemSuspend API besteht aus zwei Schnittstellen. Die HIDL-Schnittstelle wird von nativen Prozessen verwendet, um Wake Locks zu erhalten, 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 einen Wake Lock anfordert, erhält eine eindeutige IWakeLock-Instanz. Das unterscheidet sich von /sys/power/wake_lock, wodurch mehrere Clients das Wake Lock unter demselben Namen verwenden können. Wenn ein Client mit einer IWakeLock-Instanz beendet wird, wird sie vom Binder-Treiber und vom SystemSuspend-Dienst bereinigt.

AIDL-Schnittstelle ISuspendControlService

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 folgende Vorteile:

  • Wenn ein Prozess, der das Anhalten blockiert, beendet wird, kann SystemSuspend benachrichtigt werden.
  • Dem Thread, der für das Anhalten des Systems verantwortlich ist, kann ein Callback zugewiesen werden.