En Android 9 y versiones anteriores, hay un subproceso en libsuspend responsable de iniciar la suspensión del sistema. Android 10 presenta una funcionalidad equivalente en un servicio HIDL SystemSuspend. Este servicio se encuentra en la imagen del sistema y es atendido por la plataforma Android. La lógica de libsuspend
sigue siendo básicamente la misma, excepto que todos los procesos del espacio de usuario que bloquean la suspensión del sistema deben comunicarse con SystemSuspend.
libsuspend y libpower
En Android 10, el servicio SystemSuspend reemplaza a libsuspend
. libpower
se volvió a implementar 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 release_wake_lock
acquire_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 de la cantidad de bloqueos de activación emitidos con un contador de suspensión. Tiene dos hilos de ejecución:
- El subproceso principal responde a las llamadas de carpeta.
- El subproceso de suspensión controla la suspensión del sistema.
Hilo principal
El subproceso 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 subproceso de suspensión realiza lo siguiente en un bucle:
- Leer desde
/sys/ power /wakeup_count
. - Adquirir el mutex. Esto asegura que el subproceso de suspensión no toque el contador de suspensión mientras el subproceso 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, vuelve al principio del bucle. - Inicie la suspensión del sistema escribiendo
mem
en/sys/power/ state
. - Suelte el mutex.
Cuando se devuelve correctamente una solicitud de bloqueo de activación, se bloquea el subproceso de suspensión.
API de suspensión del sistema
La API SystemSuspend consta de dos interfaces. Los procesos nativos utilizan la interfaz HIDL para adquirir wake locks y la interfaz AIDL se utiliza para la comunicación entre SystemServer y SystemSuspend.
Interfaz ISystemSuspend HIDL
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 wake lock recibe una instancia única de IWakeLock
. Esto es diferente de /sys/ power /wake_lock
, que permite que varios clientes usen el bloqueo de activación con el mismo nombre. Si un cliente que tiene una instancia de IWakeLock
finaliza, el controlador de carpeta y el servicio SystemSuspend lo limpian.
Interfaz ISuspendControlService AIDL
ISuspendControlService está destinado a ser utilizado únicamente por SystemServer.
interface ISuspendCallback {
void notifyWakeup(boolean success);
}
interface ISuspendControlService {
boolean enableAutosuspend();
boolean registerCallback(ISuspendCallback callback);
boolean forceSuspend();
}
Aprovechar Android HIDL ofrece los siguientes beneficios:
- Si un proceso de bloqueo de suspensión muere, se puede notificar a SystemSuspend.
- El subproceso responsable de la suspensión del sistema puede recibir una devolución de llamada.