Android 7.0 refactorizó la capa de interfaz de radio (RIL) con un conjunto de funciones para mejorar su funcionalidad. Se requieren cambios en el código del socio para implementar estas funciones, que son opcionales, pero se recomiendan. Los cambios de refactorización son retrocompatibles, por lo que las implementaciones anteriores de las funciones refactorizadas siguen funcionando.
La refactorización de RIL incluye las siguientes mejoras:
- Códigos de error de RIL Habilita códigos de error específicos además del código
GENERIC_FAILURE
existente. Esto ayuda a solucionar problemas, ya que proporciona información más específica sobre la causa de los errores. - Control de versiones de RIL. Proporciona información de versión más precisa y fácil de configurar.
- Comunicación de RIL con wakelocks Mejora el rendimiento de la batería del dispositivo.
Puedes implementar algunas o todas las mejoras anteriores. Para obtener más detalles, consulta los comentarios de código sobre el control de versiones de RIL en https://android.googlesource.com/platform/hardware/ril/+/main/include/telephony/ril.h
.
Implementa códigos de error de RIL mejorados
Casi todas las llamadas de solicitud de RIL pueden mostrar el código de error GENERIC_FAILURE
en respuesta a un error. Este es un problema con todas las respuestas solicitadas que muestran los OEM, lo que puede dificultar la depuración de un problema desde el informe de errores si las llamadas a RIL muestran el mismo código de error GENERIC_FAILURE
por diferentes motivos. Los proveedores pueden tardar bastante tiempo en identificar qué parte del código podría haber mostrado un código GENERIC_FAILURE
.
En Android 7.x y versiones posteriores, los OEMs pueden mostrar un valor de código de error distinto asociado con cada error diferente que actualmente se clasifica como GENERIC_FAILURE
. Los OEMs que no quieran revelar públicamente sus
códigos de error personalizados pueden mostrar errores como un conjunto distinto de números enteros (como de 1 a
x) asignados como OEM_ERROR_1
a OEM_ERROR_X
. Los proveedores deben asegurarse de que cada código de error enmascarado que se devuelve se asigne a un motivo de error único en el código. El uso de códigos de error específicos puede acelerar la depuración de RIL cada vez que el OEM muestra errores genéricos, ya que a menudo puede llevar demasiado tiempo identificar la causa exacta de un código de error GENERIC_FAILURE
(y, a veces, es imposible averiguarlo).
Además, ril.h
agrega más códigos de error para las enums RIL_LastCallFailCause
y RIL_DataCallFailCause
, de modo que el código del proveedor pueda evitar mostrar errores genéricos, como CALL_FAIL_ERROR_UNSPECIFIED
y PDP_FAIL_ERROR_UNSPECIFIED
.
Valida los códigos de error de RIL mejorados
Después de agregar códigos de error nuevos para reemplazar el código GENERIC_FAILURE
, verifica que la llamada a RIL devuelva los códigos de error nuevos en lugar de GENERIC_FAILURE
.
Implementa el control de versiones mejorado de RIL
El control de versiones de RIL en versiones anteriores de Android era problemático: la versión en sí era imprecisa, el mecanismo para informar una versión de RIL no era claro (lo que causaba que algunos proveedores informaran una versión incorrecta) y la solución para estimar la versión era propensa a errores.
En Android 7.x y versiones posteriores, ril.h
documenta todos los valores de la versión de RIL, describe la versión de RIL correspondiente y enumera todos los cambios de esa versión. Cuando se realizan cambios que corresponden a una versión de RIL, los proveedores deben actualizar su versión en el código y devolverla en RIL_REGISTER
.
Valida el control de versiones de RIL mejorado
Verifica que se devuelva la versión de RIL correspondiente a tu código de RIL durante RIL_REGISTER
(en lugar del RIL_VERSION
definido en ril.h
).
Implementa la comunicación de RIL con wakelocks
Los bloqueos de activación temporizados se usan en la comunicación de RIL de forma imprecisa, lo que afecta negativamente el rendimiento de la batería. En Android 7.x y versiones posteriores, puedes mejorar el rendimiento clasificando las solicitudes de RIL y actualizando el código para controlar los bloqueos de activación de manera diferente para los diferentes tipos de solicitudes.
Cómo clasificar las solicitudes de RIL
Las solicitudes del RIL pueden ser solicitadas o no solicitadas. Los proveedores deben clasificar las solicitudes solicitadas como una de las siguientes opciones:
- síncrono. Las solicitudes que no demoran mucho tiempo en responder Por ejemplo,
RIL_REQUEST_GET_SIM_STATUS
. - asíncrono. Solicitudes que tardan un tiempo considerable en responder. Por ejemplo,
RIL_REQUEST_QUERY_AVAILABLE_NETWORKS
.
Las solicitudes RIL solicitadas asíncronas pueden tardar bastante tiempo. Después de recibir un acuse de recibo del código del proveedor, RIL Java libera el bloqueo de activación, lo que podría hacer que el procesador de la app pase del estado inactivo al estado suspendido. Cuando la respuesta está disponible desde el código del proveedor, RIL Java (el procesador de la app) vuelve a adquirir el bloqueo de activación, procesa la respuesta y, luego, vuelve al estado inactivo. Este cambio de inactivo a suspendido a inactivo puede consumir mucha energía.
Si el tiempo de respuesta no es lo suficientemente largo, mantener el bloqueo de activación y permanecer inactivo durante todo el tiempo que tarda en responder puede ser más eficiente en términos de energía que pasar al estado suspendido liberando el bloqueo de activación y activando cuando llega la respuesta. Los proveedores deben usar mediciones de energía específicas de la plataforma para determinar el valor umbral del tiempo T cuando la energía que se consume por permanecer inactivo durante todo el tiempo T es mayor que la energía que se consume cuando se pasa de inactivo a suspendido y a inactivo en el mismo tiempo T. Cuando se conoce el tiempo T, los comandos de RIL que tardan más que el tiempo T se pueden clasificar como asíncronos y los comandos restantes se pueden clasificar como síncronos.
Situaciones de comunicación de RIL
En los siguientes diagramas, se ilustran situaciones comunes de comunicación del RIL y se proporcionan soluciones para modificar el código para controlar las solicitudes solicitadas y no solicitadas del RIL.
Nota: Para obtener detalles de la implementación de las funciones que se usan en los siguientes diagramas, consulta los métodos acquireWakeLock()
, decrementWakeLock()
y clearWakeLock(
en ril.cpp
.
Situación: Solicitud de RIL y respuesta asíncrona solicitada
En esta situación, si se espera que la respuesta solicitada del RIL demore un tiempo considerable (es decir, una respuesta a RIL_REQUEST_GET_AVAILABLE_NETWORKS
), el bloqueo de activación se mantiene durante mucho tiempo en el procesador de la app. Los problemas del módem también pueden generar una espera prolongada.
Solución 1: El módem mantiene el bloqueo de activación para la solicitud de RIL y la respuesta asíncrona.
- Se envía la solicitud de RIL y el módem adquiere el bloqueo de activación para procesarla.
- El módem envía un acuse de recibo que hace que el lado de Java disminuya el contador de bloqueo de activación y lo libere cuando el valor del contador sea 0.
Nota: La duración del tiempo de espera de wakelock para la secuencia de solicitud-acuse de recibo sería menor que la duración del tiempo de espera que se usa actualmente, ya que el acuse de recibo debería recibirse con bastante rapidez.
- Después de procesar la solicitud, el módem envía una interrupción al código del proveedor que adquiere el bloqueo de activación y envía una respuesta a ril.cpp, que, a su vez, adquiere el bloqueo de activación y envía una respuesta al lado de Java.
- Cuando la respuesta llega al lado de Java, se adquiere el bloqueo de activación y se muestra una respuesta al emisor.
- Después de que todos los módulos procesan la respuesta, se envía la confirmación (a través de un socket) a
ril.cpp
, que luego libera el bloqueo de activación adquirido en el paso 3.
Solución 2: El módem no mantiene el bloqueo de activación y la respuesta es rápida (solicitud y respuesta de RIL síncronas). El comportamiento síncrono frente al asíncrono está codificado para un comando RIL específico y se decide de forma individual.
- Para enviar la solicitud de RIL, se llama a
acquireWakeLock()
en el lado de Java. - El código del proveedor no necesita adquirir un bloqueo de activación y puede procesar la solicitud y responder rápidamente.
- Cuando el lado Java recibe la respuesta, se llama a
decrementWakeLock()
, lo que disminuye el contador de bloqueo de activación y lo libera si el valor del contador es 0.
Situación: Respuesta no solicitada del RIL
En esta situación, las respuestas no solicitadas de RIL tienen una marca de tipo de bloqueo de activación que indica si se debe adquirir un bloqueo de activación para la respuesta del proveedor. Si se establece la marca, se establece un bloqueo de activación temporizado y la respuesta se envía a través de un socket al lado de Java. Cuando vence el temporizador, se libera el bloqueo de activación. El bloqueo de activación programado podría ser demasiado largo o demasiado corto para diferentes respuestas no solicitadas del RIL.
Solución: Se envía una confirmación desde el código Java al lado nativo (ril.cpp
) en lugar de mantener un bloqueo de activación temporizado en el lado nativo mientras se envía una respuesta no solicitada.
Valida los wakelocks rediseñados
Verifica que las llamadas de RIL se identifiquen como síncronas o asíncronas. Debido a que el consumo de energía de la batería puede depender del hardware o la plataforma, los proveedores deben realizar algunas pruebas internas para averiguar si el uso de la nueva semántica de bloqueo de activación para llamadas asíncronas genera ahorros de energía de la batería.