Zawieszenie systemu

W Androidzie 9 i starszych wersjach znajduje się wątek w bibliotece libsuspend. odpowiedzialnym za zainicjowanie zawieszenia systemu. Android 10 Wprowadzenie analogicznej funkcji w usłudze HIDL w systemie zawieszenia systemu. Ta usługa znajduje się w obrazie systemu i jest obsługiwana przez platformę Androida. Logika w libsuspend pozostaje w dużej mierze taka sama, z wyjątkiem każdej przestrzeni użytkownika. proces blokujący zawieszenie systemu musi komunikować się z zawieszeniem systemu.

libsuspend i libpower

W Androidzie 10 usługa Zawieszanie systemu zastępuje libsuspend Ponownie wdrożono libpower, aby korzystać z zawieszenia systemu, a nie /sys/power/wake[un]lock bez zmiany interfejsu C API.

Ten pseudokod pokazuje, jak wdrożyć 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 wykonania

Usługa zawieszania systemu śledzi liczbę blokad uśpienia przyznawanych za pomocą licznika zawieszenia. Ma dwa wątki:

  • Wątek główny odpowiada na wywołania Binder.
  • Zawieszanie powoduje zawieszenie wątku w systemie.

Wątek główny

Wątek główny odpowiada na prośby klientów o przypisanie nowych blokad uśpienia, zwiększając/zmniejszając wartość licznika zawieszenia.

Zawieś wątek

Wątek zawieszania wykonuje w pętli te działania:

  1. Przeczytaj od: /sys/power/wakeup_count.
  2. Przejęcie muteksa. Dzięki temu zawieszony wątek nie zostanie dotknięty licznik zawieszenia, gdy wątek główny próbuje wykonać możesz zwiększyć lub zmniejszyć tę wartość. Wątek główny jest zablokowany. przy uruchamianiu lub usuwaniu blokad uśpienia, gdy licznik zawieszenia wyzeruje wartość i próbuje uruchomić wątek suspend.
  3. Zaczekaj, aż licznik zdarzeń 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 uda, wróć na początek pętli.
  5. Rozpocznij zawieszanie systemu, wpisując mem w /sys/power/state
  6. Zwolnij przycisk mutex.

Po zwróceniu żądania blokady uśpienia wątek zawieszenia Użytkownik został zablokowany.

Rysunek 1. Zawieś pętlę wątku

Interfejs API zawieszania systemu

Interfejs Systemsusp API składa się z 2 interfejsów. Używany jest interfejs HIDL. przez natywne procesy do uzyskiwania blokad uśpienia. Interfejs AIDL jest używany do komunikacji między serwerem systemu a zawieszeniem systemu.

Interfejs ISystemZawieszenie HIDL


enum WakeLockType : uint32_t {
    PARTIAL,
    FULL
};

interface IWakeLock {
    oneway release();
};

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

Każdy klient, który zażąda blokady uśpienia, otrzymuje unikalny identyfikator IWakeLock instancja. Różni się od /sys/power/wake_lock, która umożliwia wiele do używania blokady uśpienia pod tą samą nazwą. Jeśli klient trzymający Zatrzymanie działania instancji IWakeLock, sterownik bindera i Usługa Zawieszanie systemu wyczyści to.

Interfejs ISuspensionControlService AIDL

Parametr IsuspControlService jest przeznaczony do używania tylko przez serwer SystemServer.


interface ISuspendCallback {
     void notifyWakeup(boolean success);
}

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

Stosowanie HIDL na Androidzie zapewnia następujące korzyści:

  • Jeśli proces blokowania zawiesza się, można powiadomić o tym fakcie.
  • Wątek odpowiedzialny za zawieszenie systemu może otrzymać wywołanie zwrotne.