In Android 9 e versioni precedenti è presente un thread in libsuspend responsabile dell'avvio della sospensione del sistema. Android 10 introduce una funzionalità equivalente in un servizio HIDL SystemSuspend.
Questo servizio si trova nell'immagine di sistema ed è fornito dalla piattaforma Android.
La logica di libsuspend
rimane in gran parte la stessa, tranne per il fatto che ogni processo dello spazio utente che blocca la sospensione del sistema deve comunicare con SystemSospendi.
libsuspend e libpower
In Android 10, il servizio SystemSuspend sostituisce
libsuspend
. libpower
è stato reimplementato in modo da fare affidamento sul servizio SystemSuspend anziché su /sys/power/wake[un]lock
senza modificare l'API C.
Questo pseudocodice mostra come implementare acquire_wake_lock
e 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;
}
Thread di esecuzione
Il servizio SystemSospendi tiene traccia del numero di wakelock emesso con un contatore di sospensione. Ha due thread di esecuzione:
- Il thread principale risponde alle chiamate a Binder.
- Il sistema di controllo dei thread sospendi viene sospeso.
Thread principale
Il thread principale risponde alle richieste dei client di allocare nuovi blocchi di risveglio, incrementando/decrementando il contatore di sospensione.
Sospendi thread
Il thread di sospensione esegue quanto segue in un ciclo:
- Leggi da
/sys/power/wakeup_count
. - Acquisisci il mutex. In questo modo, il thread di sospensione non tocca il contatore di sospensione mentre il thread principale tenta di incrementarlo o decrementarlo. Il thread principale è bloccato durante l'emissione o la rimozione di blocchi di attivazione quando il contatore di sospensione ha raggiunto lo zero e il thread sospendi sta tentando di essere eseguito.
- Attendi che il contatore sia uguale a zero.
- Scrivi il valore letto da
/sys/power /wakeup_count
(dal passaggio 1) in questo file. Se la scrittura non va a buon fine, torna all'inizio del loop - Avvia la sospensione del sistema scrivendo
mem
in/sys/power/state
. - Rilascia il silenziatore.
Quando una richiesta di blocco di riattivazione viene restituita correttamente, il thread di sospensione viene bloccato.
API SystemSuspend
L'API SystemSuspend è composta da due interfacce. L'interfaccia HIDL viene utilizzata dai processi nativi per acquisire i blocchi di riattivazione e l'interfaccia AIDL viene utilizzata per la comunicazione tra SystemServer e SystemSuspend.
Interfaccia HIDL ISystemSuspend
enum WakeLockType : uint32_t {
PARTIAL,
FULL
};
interface IWakeLock {
oneway release();
};
interface ISystemSuspend {
acquireWakeLock(WakeLockType type, string debugName)
generates (IWakeLock lock);
};
Ogni client che richiede un blocco di attivazione riceve un'istanza IWakeLock
univoca. È diverso da /sys/power/wake_lock
, che consente a più client di utilizzare il blocco di attivazione con lo stesso nome. Se un client che gestisce un'istanza IWakeLock
termina, il driver del binder e il servizio SystemSuspend la ripuliscono.
Interfaccia AIDL ISuspendControlService
ISuspendControlService è destinato all'utilizzo solo da parte di SystemServer.
interface ISuspendCallback {
void notifyWakeup(boolean success);
}
interface ISuspendControlService {
boolean enableAutosuspend();
boolean registerCallback(ISuspendCallback callback);
boolean forceSuspend();
}
L'utilizzo di Android HIDL offre i seguenti vantaggi:
- Se un processo di blocco della sospensione si arresta in modo anomalo, SystemSuspend può ricevere una notifica.
- È possibile assegnare un callback al thread responsabile della sospensione del sistema.