Usługa SystemSuspend

W Androidzie 9 i niższych w libsuspend znajduje się wątek odpowiedzialny za inicjowanie zawieszenia systemu. Android 10 wprowadza równoważną funkcjonalność w usłudze SystemSuspend HIDL. Usługa ta zlokalizowana jest w obrazie systemu i obsługiwana jest przez platformę Android. Logika libsuspend pozostaje w dużej mierze taka sama, z tym wyjątkiem, że każdy proces przestrzeni użytkownika blokujący zawieszenie systemu musi komunikować się z SystemSuspend.

libsuspend i libpower

W systemie Android 10 usługa SystemSuspend zastępuje libsuspend . libpower została ponownie zaimplementowana tak, aby opierała się na usłudze SystemSuspend zamiast /sys/ power /wake[un]lock bez zmiany interfejsu API języka C.

Ten pseudokod pokazuje, jak zaimplementować acquire_wake_lock i release_wake_lock .


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;
}

Wątki wykonawcze

Usługa SystemSuspend śledzi liczbę blokad uśpienia wydanych za pomocą licznika zawieszeń. Ma dwa wątki wykonania:

  • Główny wątek odpowiada na wywołania segregatora.
  • Wątek zawieszenia steruje zawieszeniem systemu.

Główny wątek

Główny wątek odpowiada na żądania klientów dotyczące przydzielenia nowych blokad uśpienia, zwiększając/zmniejszając licznik zawieszeń.

Zawieś wątek

Wątek zawieszający wykonuje w pętli następujące czynności:

  1. Przeczytaj z /sys/ power /wakeup_count .
  2. Zdobądź muteks. Dzięki temu wątek zawieszający nie dotknie licznika zawieszeń, podczas gdy wątek główny próbuje go zwiększyć lub zmniejszyć. Główny wątek jest blokowany przy wystawianiu lub usuwaniu blokad uśpienia, gdy licznik zawieszeń osiągnął zero, a wątek zawieszający próbuje uruchomić.
  3. Poczekaj, aż licznik będzie równy zero.
  4. Zapisz do tego pliku wartość odczytaną z /sys/ power /wakeup_count (z kroku 1). Jeśli zapis się nie powiedzie, wróć na początek pętli
  5. Uruchom zawieszenie systemu, pisząc mem do /sys/power/ state .
  6. Zwolnij muteks.

Gdy żądanie blokady uśpienia zostanie pomyślnie zwrócone, wątek zawieszający zostanie zablokowany.

Rysunek 1. Zawieś pętlę nici

SystemZawieś API

Interfejs API SystemSuspend składa się z dwóch interfejsów. Interfejs HIDL jest używany przez procesy natywne do uzyskiwania blokad uśpienia, a interfejs AIDL służy do komunikacji pomiędzy serwerem SystemServer i SystemSuspend.

ISystemZawieś interfejs HIDL


enum WakeLockType : uint32_t {
    PARTIAL,
    FULL
};

interface IWakeLock {
    oneway release();
};

interface ISystemSuspend {
    acquireWakeLock(WakeLockType type, string debugName)
        generates (IWakeLock lock);
};

Każdy klient żądający blokady wybudzania otrzymuje unikalną instancję IWakeLock . Różni się to od /sys/ power /wake_lock , który umożliwia wielu klientom korzystanie z blokady wybudzania pod tą samą nazwą. Jeśli klient przechowujący instancję IWakeLock zakończy działanie, sterownik segregatora i usługa SystemSuspend czyści ją.

Interfejs AIDL ISuspendControlService

Usługa ISuspendControlService jest przeznaczona do użytku wyłącznie przez serwer SystemServer.


interface ISuspendCallback {
     void notifyWakeup(boolean success);
}

interface ISuspendControlService {
    boolean enableAutosuspend();
    boolean registerCallback(ISuspendCallback callback);
    boolean forceSuspend();
}

Wykorzystanie Androida HIDL oferuje następujące korzyści:

  • Jeśli proces blokujący zawieszenie zakończy się, można powiadomić SystemSuspend.
  • Wątkowi odpowiedzialnemu za zawieszenie systemu można nadać wywołanie zwrotne.