En Android 9 y versiones anteriores hay un hilo en libsuspend responsable de iniciar la suspensión del sistema. Android 10 introduce una funcionalidad equivalente en un servicio SystemSuspend HIDL. Este servicio está ubicado en la imagen del sistema y es atendido por la plataforma Android. La lógica de libsuspend
sigue siendo prácticamente la misma, excepto que cada proceso del espacio de usuario que bloquea la suspensión del sistema necesita comunicarse con SystemSuspend.
libsuspend y libpower
En Android 10, el servicio SystemSuspend reemplaza libsuspend
. libpower
se reimplementó para depender del servicio SystemSuspend en lugar de /sys/ power /wake[un]lock
sin cambiar la API de C.
Este pseudocódigo muestra cómo implementar acquire_wake_lock
y 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;
}
Hilos de ejecución
El servicio SystemSuspend realiza un seguimiento del número de bloqueos de activación emitidos con un contador de suspensión. Tiene dos hilos de ejecución:
- El hilo principal responde a las llamadas de carpeta.
- El hilo de suspensión controla la suspensión del sistema.
Hilo principal
El hilo principal responde a las solicitudes de los clientes para asignar nuevos bloqueos de activación, incrementando/disminuyendo el contador de suspensión.
suspender hilo
El hilo suspendido realiza lo siguiente en un bucle:
- Leer desde
/sys/ power /wakeup_count
. - Adquirir el mutex. Esto asegura que el hilo de suspensión no toque el contador de suspensión mientras el hilo principal intenta incrementarlo o disminuirlo. El subproceso principal se bloquea al emitir o eliminar bloqueos de activación cuando el contador de suspensión ha llegado a cero y el subproceso de suspensión está intentando ejecutarse.
- Espere hasta que el contador sea igual a cero.
- Escriba el valor leído de
/sys/ power /wakeup_count
(del paso 1) en este archivo. Si la escritura falla, regrese al comienzo del ciclo. - Inicie la suspensión del sistema escribiendo
mem
en/sys/power/ state
. - Libere el mutex.
Cuando una solicitud de bloqueo de activación regresa con éxito, el hilo de suspensión se bloquea.
API de suspensión del sistema
La API SystemSuspend consta de dos interfaces. Los procesos nativos utilizan la interfaz HIDL para adquirir bloqueos de activación y la interfaz AIDL se utiliza para la comunicación entre SystemServer y SystemSuspend.
Interfaz HIDL ISystemSuspend
enum WakeLockType : uint32_t {
PARTIAL,
FULL
};
interface IWakeLock {
oneway release();
};
interface ISystemSuspend {
acquireWakeLock(WakeLockType type, string debugName)
generates (IWakeLock lock);
};
Cada cliente que solicita un bloqueo de activación recibe una instancia única IWakeLock
. Esto es diferente de /sys/ power /wake_lock
, que permite que varios clientes utilicen el bloqueo de activación con el mismo nombre. Si un cliente que posee una instancia IWakeLock
finaliza, el controlador de carpeta y el servicio SystemSuspend lo limpian.
Interfaz ISuspendControlService AIDL
ISuspendControlService está diseñado para ser utilizado únicamente por SystemServer.
interface ISuspendCallback {
void notifyWakeup(boolean success);
}
interface ISuspendControlService {
boolean enableAutosuspend();
boolean registerCallback(ISuspendCallback callback);
boolean forceSuspend();
}
Aprovechar el HIDL de Android ofrece los siguientes beneficios:
- Si un proceso de suspensión y bloqueo muere, se puede notificar a SystemSuspend.
- Al hilo responsable de la suspensión del sistema se le puede devolver una llamada.