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:
- Przeczytaj z
/sys/ power /wakeup_count
. - 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ć.
- Poczekaj, aż licznik będzie równy zero.
- 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 - Uruchom zawieszenie systemu, pisząc
mem
do/sys/power/ state
. - Zwolnij muteks.
Gdy żądanie blokady uśpienia zostanie pomyślnie zwrócone, wątek zawieszający zostanie zablokowany.
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.