Refactorisation RIL

Android 7.0 a refactorisé la couche d'interface radio (RIL) à l'aide d'un ensemble de fonctionnalités pour améliorer son fonctionnement. Des modifications du code du partenaire sont requises pour implémenter ces fonctionnalités, qui sont facultatives, mais recommandées. Les modifications de refactorisation sont rétrocompatibles. Les implémentations précédentes des fonctionnalités refactorisées continuent donc de fonctionner.

Le refactoring du RIL inclut les améliorations suivantes:

  • Codes d'erreur RIL Active des codes d'erreur spécifiques en plus du code GENERIC_FAILURE existant. Cela facilite le dépannage des erreurs en fournissant des informations plus spécifiques sur la cause des erreurs.
  • Gestion des versions du RIL. Fournit des informations sur les versions plus précises et plus faciles à configurer.
  • Communication RIL à l'aide de wakelocks. Améliore les performances de la batterie de l'appareil.

Vous pouvez implémenter l'une ou l'ensemble des améliorations ci-dessus. Pour en savoir plus, consultez les commentaires de code sur la gestion des versions RIL dans https://android.googlesource.com/platform/hardware/ril/+/main/include/telephony/ril.h.

Implémenter des codes d'erreur RIL améliorés

Presque tous les appels de requête RIL peuvent renvoyer le code d'erreur GENERIC_FAILURE en réponse à une erreur. Il s'agit d'un problème lié à toutes les réponses sollicitées renvoyées par les OEM, ce qui peut rendre difficile le débogage d'un problème à partir du rapport de bug si le même code d'erreur GENERIC_FAILURE est renvoyé par les appels RIL pour différentes raisons. Il peut s'écouler un temps considérable avant que les fournisseurs puissent même identifier la partie du code qui a pu renvoyer un code GENERIC_FAILURE.

Sous Android 7.x et versions ultérieures, les OEM peuvent renvoyer une valeur de code d'erreur distincte associée à chaque erreur différente actuellement classée comme GENERIC_FAILURE. Les OEM qui ne souhaitent pas révéler publiquement leurs codes d'erreur personnalisés peuvent renvoyer des erreurs en tant qu'ensemble distinct d'entiers (par exemple, de 1 à x) mappés de OEM_ERROR_1 à OEM_ERROR_X. Les fournisseurs doivent s'assurer que chaque code d'erreur masqué renvoyé correspond à une raison d'erreur unique dans le code. L'utilisation de codes d'erreur spécifiques peut accélérer le débogage du RIL chaque fois que l'OEM renvoie des erreurs génériques, car il peut souvent prendre trop de temps pour identifier la cause exacte d'un code d'erreur GENERIC_FAILURE (et parfois, il est impossible de le savoir).

En outre, ril.h ajoute d'autres codes d'erreur pour les énumérations RIL_LastCallFailCause et RIL_DataCallFailCause afin que le code du fournisseur puisse éviter de renvoyer des erreurs génériques telles que CALL_FAIL_ERROR_UNSPECIFIED et PDP_FAIL_ERROR_UNSPECIFIED.

Valider les codes d'erreur RIL améliorés

Après avoir ajouté de nouveaux codes d'erreur pour remplacer le code GENERIC_FAILURE, vérifiez que les nouveaux codes d'erreur sont renvoyés par l'appel RIL au lieu de GENERIC_FAILURE.

Implémenter une gestion des versions RIL améliorée

La gestion des versions RIL dans les anciennes versions d'Android était problématique: la version elle-même était imprécise, le mécanisme de signalement d'une version RIL était peu clair (ce qui a amené certains fournisseurs à signaler une version incorrecte), et le correctif permettant d'estimer la version était sujet à des erreurs.

Sous Android 7.x et versions ultérieures, ril.h documente toutes les valeurs de version RIL, décrit la version RIL correspondante et liste toutes les modifications apportées à cette version. Lorsque vous apportez des modifications qui correspondent à une version de RIL, les fournisseurs doivent mettre à jour leur version en code et la renvoyer dans RIL_REGISTER.

Valider la gestion des versions RIL améliorée

Vérifiez que la version RIL correspondant à votre code RIL est renvoyée lors de RIL_REGISTER (plutôt que le RIL_VERSION défini dans ril.h).

Implémenter la communication RIL à l'aide de wakelocks

Les wakelocks temporisés sont utilisés de manière imprécise dans la communication RIL, ce qui a un impact négatif sur les performances de la batterie. Sous Android 7.x et versions ultérieures, vous pouvez améliorer les performances en classant les requêtes RIL et en mettant à jour le code pour gérer les wakelocks différemment selon les types de requêtes.

Classer les requêtes RIL

Les requêtes RIL peuvent être sollicitées ou non sollicitées. Les fournisseurs doivent classer les demandes sollicitées comme suit:

  • synchrone. Requêtes dont la réponse ne prend pas beaucoup de temps Par exemple, RIL_REQUEST_GET_SIM_STATUS.
  • asynchrone. Requêtes dont la réponse prend beaucoup de temps Par exemple, RIL_REQUEST_QUERY_AVAILABLE_NETWORKS.

Les requêtes RIL sollicitées asynchrones peuvent prendre un temps considérable. Après avoir reçu un accusé de réception du code du fournisseur, RIL Java libère le wakelock, ce qui peut entraîner le passage du processeur de l'application de l'état d'inactivité à l'état de suspension. Lorsque la réponse est disponible à partir du code du fournisseur, RIL Java (le processeur d'application) récupère à nouveau le wakelock, traite la réponse, puis revient à l'état inactif. Ce passage de l'état d'inactivité à l'état de suspension à l'état d'inactivité peut consommer beaucoup d'énergie.

Si le temps de réponse n'est pas assez long, maintenir le wakelock et rester en veille pendant toute la durée de la réponse peut être plus économe en énergie que de passer en état de suspension en libérant le wakelock et de le réveiller lorsque la réponse arrive. Les fournisseurs doivent utiliser des mesures d'alimentation spécifiques à la plate-forme pour déterminer la valeur seuil de l'heure T lorsque la consommation d'énergie en mode veille pendant toute la durée T est supérieure à la consommation d'énergie lors du passage de l'état veille à l'état suspendu et à l'état veille au cours de la même durée T. Lorsque l'heure T est connue, les commandes RIL qui prennent plus de temps que l'heure T peuvent être classées comme asynchrones et les commandes restantes comme synchrones.

Scénarios de communication RIL

Les schémas suivants illustrent des scénarios de communication RIL courants et fournissent des solutions pour modifier le code afin de gérer les requêtes sollicitées et non sollicitées du RIL.

Remarque:Pour en savoir plus sur l'implémentation des fonctions utilisées dans les diagrammes suivants, consultez les méthodes acquireWakeLock(), decrementWakeLock() et clearWakeLock( dans ril.cpp.

Scénario: Requête RIL et réponse asynchrone sollicitée

Dans ce scénario, si la réponse sollicitée par le RIL prend un temps considérable (par exemple, une réponse à RIL_REQUEST_GET_AVAILABLE_NETWORKS), le wakelock est maintenu pendant une longue période du côté du processeur de l'application. Des problèmes de modem peuvent également entraîner une longue attente.

Figure 1. RIL a demandé une réponse asynchrone.

Solution 1:Le modem maintient le wakelock pour la requête RIL et la réponse asynchrone.

Figure 2. Wakelock détenu par le modem.
  1. La requête RIL est envoyée et le modem acquiert un wakelock pour traiter cette requête.
  2. Le modem envoie une confirmation qui entraîne une diminution du compteur de wakelock côté Java et sa libération lorsque la valeur du compteur est de 0.

    Remarque:La durée du délai avant expiration du wakelock pour la séquence de requête-acquittement est inférieure à la durée de délai avant expiration actuellement utilisée, car l'acquittement doit être reçu assez rapidement.

  3. Après avoir traité la requête, le modem envoie une interruption au code du fournisseur qui acquiert le wakelock et envoie une réponse à ril.cpp, qui à son tour acquiert le wakelock et envoie une réponse côté Java.
  4. Lorsque la réponse atteint le côté Java, le wakelock est acquis et une réponse est renvoyée à l'appelant.
  5. Une fois la réponse traitée par tous les modules, une confirmation est renvoyée (via un socket) à ril.cpp, qui libère ensuite le wakelock acquis à l'étape 3.

Solution 2:Le modem ne maintient pas le wakelock et la réponse est rapide (requête et réponse RIL synchrones). Le comportement synchrone ou asynchrone est codé en dur pour une commande RIL spécifique et décidé sur une base d'appel par appel.

Figure 3. Wakelock non détenu par le modem.
  1. La requête RIL est envoyée en appelant acquireWakeLock() côté Java.
  2. Le code du fournisseur n'a pas besoin d'acquérir un wakelock et peut traiter la requête et répondre rapidement.
  3. Lorsque la réponse est reçue côté Java, decrementWakeLock() est appelé, ce qui diminue le compteur de wakelock et libère le wakelock si la valeur du compteur est 0.

Scénario: Réponse non sollicitée du RIL

Dans ce scénario, les réponses non sollicitées du RIL comportent un indicateur de type de wakelock qui indique si un wakelock doit être acquis pour la réponse du fournisseur. Si l'indicateur est défini, un wakelock temporisé est défini et la réponse est envoyée via un socket côté Java. Lorsque le minuteur expire, le wakelock est libéré. Le wakelock temporisé peut être trop long ou trop court pour différentes réponses non sollicitées du RIL.

Figure 4. Réponse non sollicitée de l'RIL.

Solution:Une confirmation est envoyée du code Java au côté natif (ril.cpp) au lieu de maintenir un wakelock temporisé côté natif lors de l'envoi d'une réponse non sollicitée.

Figure 5 : Utilisation d'un accusé de réception au lieu d'un wakelock temporisé.

Valider les wakelocks repensés

Vérifiez que les appels RIL sont identifiés comme synchrones ou asynchrones. Étant donné que la consommation d'énergie de la batterie peut dépendre du matériel/de la plate-forme, les fournisseurs doivent effectuer des tests internes pour déterminer si l'utilisation des nouvelles sémantiques de wakelock pour les appels asynchrones permet d'économiser de l'énergie de la batterie.