Dans Android 9 et versions antérieures, il existe un thread dans libsuspend chargé de lancer la suspension du système. Android 10 introduit une fonctionnalité équivalente dans un service SystemSuspend HIDL. Ce service est situé dans l'image système et est servi par la plateforme Android. La logique de libsuspend
reste en grande partie la même, sauf que chaque processus de l'espace utilisateur bloquant la suspension du système doit communiquer avec SystemSuspend.
libsuspend et libpower
Dans Android 10, le service SystemSuspend remplace libsuspend
. libpower
a été réimplémenté pour s'appuyer sur le service SystemSuspend au lieu de /sys/ power /wake[un]lock
sans modifier l'API C.
Ce pseudocode montre comment implémenter acquire_wake_lock
et 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;
}
Fils d'exécution
Le service SystemSuspend garde une trace du nombre de wakelocks émis avec un compteur de suspension. Il a deux threads d'exécution :
- Le thread principal répond aux appels du classeur.
- Le thread de suspension contrôle la suspension du système.
Fil principal
Le thread principal répond aux demandes des clients pour allouer de nouveaux wakelocks, en incrémentant/décrémentant le compteur de suspension.
Suspendre le fil de discussion
Le thread de suspension effectue les opérations suivantes en boucle :
- Lire depuis
/sys/ power /wakeup_count
. - Acquérir le mutex. Cela garantit que le thread de suspension ne touche pas le compteur de suspension pendant que le thread principal tente de l'incrémenter ou de le décrémenter. Le thread principal est bloqué lors de l'émission ou de la suppression de wakelocks lorsque le compteur de suspension a atteint zéro et que le thread de suspension tente de s'exécuter.
- Attendez que le compteur soit égal à zéro.
- Écrivez la valeur lue dans
/sys/ power /wakeup_count
(de l'étape 1) dans ce fichier. Si l'écriture échoue, revenez au début de la boucle - Démarrez la suspension du système en écrivant
mem
dans/sys/power/ state
. - Relâchez le mutex.
Lorsqu'une demande de wakelock est renvoyée avec succès, le thread de suspension est bloqué.
API SystemSuspend
L'API SystemSuspend se compose de deux interfaces. L'interface HIDL est utilisée par les processus natifs pour acquérir des wakelocks et l'interface AIDL est utilisée pour la communication entre SystemServer et SystemSuspend.
Interface ISystemSuspend HIDL
enum WakeLockType : uint32_t {
PARTIAL,
FULL
};
interface IWakeLock {
oneway release();
};
interface ISystemSuspend {
acquireWakeLock(WakeLockType type, string debugName)
generates (IWakeLock lock);
};
Chaque client qui demande un wakelock reçoit une instance IWakeLock
unique. Ceci est différent de /sys/ power /wake_lock
, qui permet à plusieurs clients d'utiliser le wakelock sous le même nom. Si un client détenant une instance IWakeLock
se termine, le pilote de classeur et le service SystemSuspend le nettoient.
Interface AIDL ISuspendControlService
ISuspendControlService est destiné à être utilisé uniquement par SystemServer.
interface ISuspendCallback {
void notifyWakeup(boolean success);
}
interface ISuspendControlService {
boolean enableAutosuspend();
boolean registerCallback(ISuspendCallback callback);
boolean forceSuspend();
}
L’exploitation d’Android HIDL offre les avantages suivants :
- Si un processus de blocage de suspension s'arrête, SystemSuspend peut être averti.
- Le thread responsable de la suspension du système peut recevoir un rappel.