In Android 9 e versioni precedenti è presente un thread in libsuspend
responsabile di avviare la sospensione del sistema. Android 10
introduce una funzionalità equivalente in un servizio HIDL SystemSospendi.
Questo servizio si trova nell'immagine di sistema ed è gestito dalla piattaforma Android.
La logica di libsuspend
rimane in gran parte la stessa, ad eccezione di ogni spazio utente
il processo che blocca la sospensione del sistema deve comunicare con SystemPause.
libsuspend e libpower
In Android 10, il servizio SystemSospendi sostituisce
libsuspend
. libpower
è stato reimplementato in modo che si basi su
al servizio SystemSospendi invece che
/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 emessi 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 per l'allocazione di nuovi wakelock, Aumenta/diminuisce il contatore di sospensione.
Sospendi thread
Il thread di sospensione esegue la seguente sequenza in un loop:
- Leggi da
/sys/power/wakeup_count
. - Acquisisci il mutex. Questo assicura che il thread di sospensione non tocchi il contatore di sospensione mentre il thread main tenta di di aumentarla o diminuirla. Il thread principale è bloccato sull'emissione o la rimozione dei wakelock quando il contatore di sospensione ha raggiunto lo zero e il thread sospendi sta tentando di eseguire.
- 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 riesce, torna all'inizio del loop - Avvia la sospensione del sistema scrivendo
mem
in/sys/power/state
. - Rilascia il silenziatore.
Quando viene restituita una richiesta di wakelock, il thread di sospensione viene bloccato.
.API SystemPause
L'API SystemSospendi è composta da due interfacce. L'interfaccia HIDL viene utilizzata dai processi nativi per acquisire i wakelock e l'interfaccia AIDL viene utilizzata la comunicazione tra SystemServer e SystemPause.
Interfaccia ISystemSospendi HIDL
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 wakelock riceve un ID univoco
IWakeLock
istanza. Questo è diverso da
/sys/power/wake_lock
, che consente
di usare il wakelock con lo stesso nome. Se un cliente che detiene una
L'istanza IWakeLock
viene terminata, il driver binder e
Il servizio SystemSospendi esegue la pulizia.
Interfaccia AIDL ISospendiControlService
ISospendiControlService è destinato a essere utilizzato solo da SystemServer.
interface ISuspendCallback {
void notifyWakeup(boolean success);
}
interface ISuspendControlService {
boolean enableAutosuspend();
boolean registerCallback(ISuspendCallback callback);
boolean forceSuspend();
}
L'uso di Android HIDL offre i seguenti vantaggi:
- Se il processo di blocco della sospensione si interrompe, può essere inviata una notifica a SystemSospendi.
- È possibile assegnare un callback al thread responsabile della sospensione del sistema.