Refactorisation RIL

Android 7.0 a refactorisé la couche d'interface radio (RIL) à l'aide d'un ensemble de fonctionnalités pour améliorer la fonctionnalité RIL. Des modifications du code partenaire sont nécessaires pour mettre en œuvre ces fonctionnalités, qui sont facultatives mais encouragées. Les modifications de refactorisation sont rétrocompatibles, de sorte que les implémentations antérieures des fonctionnalités refactorisées continuent de fonctionner.

La refactorisation 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 RIL. Fournit des informations de version plus précises et plus faciles à configurer.
  • Communication RIL utilisant des wakelocks. Améliore les performances de la batterie de l'appareil.

Vous pouvez mettre en œuvre tout ou partie des améliorations ci-dessus. Pour plus de détails, reportez-vous aux commentaires de code sur la gestion des versions RIL dans https://android.googlesource.com/platform/hardware/ril/+/main/include/telephony/ril.h .

Implémentation de 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 avec 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 bogue si le même code d'erreur GENERIC_FAILURE est renvoyé par les appels RIL pour différentes raisons. Cela peut prendre un temps considérable aux fournisseurs, ne serait-ce que pour identifier quelle partie du code aurait pu renvoyer un code GENERIC_FAILURE .

Dans 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 les erreurs sous la forme d'un ensemble distinct d'entiers (tels que 1 à x) mappés comme OEM_ERROR_1 vers OEM_ERROR_X . Les fournisseurs doivent s'assurer que chacun de ces codes d'erreur masqués renvoie des cartes vers une raison d'erreur unique dans le code. L'utilisation de codes d'erreur spécifiques peut accélérer le débogage RIL chaque fois que des erreurs génériques sont renvoyées par l'OEM, car l'identification de la cause exacte d'un code d'erreur GENERIC_FAILURE peut souvent prendre trop de temps (et il est parfois impossible de la comprendre).

De plus, ril.h ajoute plus de 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 .

Validation des 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émentation d'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 rapport d'une version RIL n'était pas clair (ce qui a amené certains fournisseurs à signaler une version incorrecte) et la solution de contournement pour estimer la version était sujette à l'inexactitude.

Sous Android 7.x et versions ultérieures, ril.h documente toutes les valeurs de version RIL, décrit la version RIL correspondante et répertorie toutes les modifications apportées à cette version. Lorsqu'ils apportent des modifications correspondant à une version de RIL, les fournisseurs doivent mettre à jour leur version dans le code et renvoyer cette version dans RIL_REGISTER .

Validation du versioning RIL amélioré

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

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

Les wakelocks temporisés sont utilisés dans la communication RIL de manière imprécise, ce qui affecte négativement 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 pour différents types de requêtes.

Classification des demandes RIL

Les demandes RIL peuvent être sollicitées ou non. Les fournisseurs doivent en outre classer les demandes sollicitées comme l'une des catégories suivantes :

  • synchrone . Des demandes qui ne prennent pas beaucoup de temps à répondre. Par exemple, RIL_REQUEST_GET_SIM_STATUS .
  • asynchrone . Des demandes qui prennent beaucoup de temps à répondre. 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 faire passer le processeur d'application de l'état inactif à l'état suspendu. Lorsque la réponse est disponible à partir du code du fournisseur, RIL Java (le processeur d'application) réacquiert le wakelock, traite la réponse, puis revient au repos. Un tel passage du mode veille à la mise en veille puis au mode veille peut consommer beaucoup d'énergie.

Si le temps de réponse n'est pas assez long, maintenir le wakelock et rester inactif pendant tout le temps nécessaire pour répondre peut être plus économe en énergie que de passer en état de suspension en relâchant le wakelock et en se réveillant lorsque la réponse arrive. Les fournisseurs doivent utiliser des mesures de puissance spécifiques à la plate-forme pour déterminer la valeur seuil du temps T lorsque la puissance consommée en restant inactif pendant toute la durée T est supérieure à la puissance consommée en passant du mode veille à la suspension et au mode veille pendant le même temps T Lorsque le temps T est connu, les commandes RIL qui prennent plus du temps T peuvent être classées comme asynchrones et les commandes restantes comme synchrones.

Scénarios de communication RIL

Les diagrammes suivants illustrent des scénarios de communication RIL courants et fournissent des solutions pour modifier le code afin de gérer les demandes RIL sollicitées et non sollicitées.

Remarque : Pour plus de détails sur l'implémentation des fonctions utilisées dans les diagrammes suivants, reportez-vous aux 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 RIL devrait prendre un temps considérable (c'est-à-dire une réponse à RIL_REQUEST_GET_AVAILABLE_NETWORKS ), le wakelock est maintenu pendant une longue période du côté du processeur d'application. Les problèmes de modem peuvent également entraîner une longue attente.

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

Solution 1 : le modem détient 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 le wakelock pour traiter cette requête.
  2. Le modem envoie un accusé de réception qui amène le côté Java à décrémenter le compteur wakelock et à le libérer lorsque la valeur du compteur est 0.

    Remarque : La durée du délai d'attente du wakelock pour la séquence de demande-accusé de réception serait inférieure à la durée du délai d'attente actuellement utilisée, car l'accusé de réception devrait être reçu assez rapidement.

  3. Après avoir traité la demande, 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 du 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, l'accusé de réception est renvoyé (via socket) à ril.cpp , qui libère ensuite le wakelock acquis à l'étape 3.

Solution 2 : Le modem ne détient 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é 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 demande et répondre rapidement.
  3. Lorsque la réponse est reçue côté Java, decrementWakeLock() est appelé, ce qui diminue le compteur wakelock et libère le wakelock si la valeur du compteur est 0.

Scénario : réponse non sollicitée de RIL

Dans ce scénario, les réponses non sollicitées RIL ont un indicateur de type 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 la minuterie expire, le wakelock est libéré. Le wakelock chronométré peut être trop long ou trop court pour différentes réponses non sollicitées de RIL.

Figure 4. Réponse non sollicitée du RIL.

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

Figure 5. Utilisation d'ack au lieu du wakelock chronométré.

Validation des 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 savoir si l'utilisation de la nouvelle sémantique wakelock pour les appels asynchrones entraîne des économies d'énergie sur la batterie.