Refactorización RIL

Android 7.0 refactorizó la capa de interfaz de radio (RIL) utilizando un conjunto de funciones para mejorar la funcionalidad de RIL. Se requieren cambios en el código de socio para implementar estas funciones, que son opcionales pero recomendables. Los cambios de refactorización son compatibles con versiones anteriores, por lo que las implementaciones anteriores de las funciones refactorizadas continúan funcionando.

La refactorización RIL incluye las siguientes mejoras:

  • Códigos de error RIL. Habilita códigos de error específicos además del código GENERIC_FAILURE existente. Esto ayuda en la resolución de errores al proporcionar información más específica sobre la causa de los errores.
  • Versionado RIL. Proporciona información de versión más precisa y más fácil de configurar.
  • Comunicación RIL mediante wakelocks. Mejora el rendimiento de la batería del dispositivo.

Puede implementar cualquiera o todas las mejoras anteriores. Para obtener más detalles, consulte los comentarios del código sobre el control de versiones de RIL en https://android.googlesource.com/platform/hardware/ril/+/main/include/telephony/ril.h .

Implementación de códigos de error RIL mejorados

Casi todas las llamadas de solicitud RIL pueden devolver el código de error GENERIC_FAILURE en respuesta a un error. Este es un problema con todas las respuestas solicitadas devueltas por los OEM, lo que puede dificultar la depuración de un problema del informe de error si las llamadas RIL devuelven el mismo código de error GENERIC_FAILURE por diferentes motivos. Los proveedores pueden tardar un tiempo considerable en identificar siquiera qué parte del código podría haber devuelto un código GENERIC_FAILURE .

En Android 7.x y versiones posteriores, los OEM pueden devolver un valor de código de error distinto asociado con cada error diferente que actualmente está categorizado como GENERIC_FAILURE . Los OEM que no quieran revelar públicamente sus códigos de error personalizados pueden devolver errores como un conjunto distinto de números enteros (como 1 a x) asignados como OEM_ERROR_1 a OEM_ERROR_X . Los proveedores deben asegurarse de que cada código de error enmascarado devuelto se corresponda con 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 devuelve 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 determinarlo).

Además, ril.h agrega más códigos de error para las enumeraciones RIL_LastCallFailCause y RIL_DataCallFailCause para que el código del proveedor pueda evitar devolver errores genéricos como CALL_FAIL_ERROR_UNSPECIFIED y PDP_FAIL_ERROR_UNSPECIFIED .

Validación de códigos de error RIL mejorados

Después de agregar nuevos códigos de error para reemplazar el código GENERIC_FAILURE , verifique que la llamada RIL devuelva los nuevos códigos de error en lugar de GENERIC_FAILURE .

Implementación de versiones RIL mejoradas

El control de versiones RIL en versiones anteriores de Android era problemático: la versión en sí era imprecisa, el mecanismo para informar una versión RIL no estaba claro (lo que provocó que algunos proveedores informaran una versión incorrecta) y la solución alternativa para estimar la versión era propensa a ser inexacta.

En Android 7.x y versiones posteriores, ril.h documenta todos los valores de la versión RIL, describe la versión RIL correspondiente y enumera todos los cambios para esa versión. Al realizar cambios que corresponden a una versión de RIL, los proveedores deben actualizar su versión en el código y devolver esa versión en RIL_REGISTER .

Validación de versiones RIL mejoradas

Verifique que la versión RIL correspondiente a su código RIL se devuelva durante RIL_REGISTER (en lugar de RIL_VERSION definida en ril.h ).

Implementación de la comunicación RIL mediante wakelocks

Los wakelocks temporizados se utilizan en la comunicación RIL de forma imprecisa, lo que afecta negativamente al rendimiento de la batería. En Android 7.x y versiones posteriores, puede mejorar el rendimiento clasificando las solicitudes RIL y actualizando el código para manejar los wakelocks de manera diferente para diferentes tipos de solicitudes.

Clasificación de solicitudes RIL

Las solicitudes RIL pueden ser solicitadas o no solicitadas. Los proveedores deben clasificar además las solicitudes solicitadas como una de las siguientes:

  • sincrónico . Solicitudes que no requieren un tiempo considerable para responder. Por ejemplo, RIL_REQUEST_GET_SIM_STATUS .
  • asincrónico . Solicitudes que tardan un tiempo considerable en responder. Por ejemplo, RIL_REQUEST_QUERY_AVAILABLE_NETWORKS .

Las solicitudes RIL solicitadas asíncronamente pueden llevar un tiempo considerable. Después de recibir una confirmación del código del proveedor, RIL Java libera el wakelock, lo que podría provocar que el procesador de la aplicación pase del estado inactivo al estado suspendido. Cuando la respuesta está disponible en el código del proveedor, RIL Java (el procesador de aplicaciones) vuelve a adquirir el wakelock, procesa la respuesta y luego vuelve al estado inactivo. Pasar de inactivo a suspendido a inactivo puede consumir mucha energía.

Si el tiempo de respuesta no es lo suficientemente largo, mantener el wakelock y permanecer inactivo durante todo el tiempo necesario para responder puede ser más eficiente desde el punto de vista energético que entrar en estado de suspensión soltando el wakelock y despertando cuando llegue la respuesta. Los proveedores deben utilizar mediciones de potencia específicas de la plataforma para determinar el valor umbral del tiempo T cuando la energía consumida al permanecer inactivo durante todo el tiempo T es mayor que la energía consumida al pasar de inactivo a suspendido y a inactivo al mismo tiempo T Cuando se conoce el tiempo T , los comandos 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.

Escenarios de comunicación RIL

Los siguientes diagramas ilustran escenarios de comunicación RIL comunes y brindan soluciones para modificar el código para manejar solicitudes solicitadas y no solicitadas de RIL.

Nota: Para obtener detalles de implementación sobre las funciones utilizadas en los siguientes diagramas, consulte los métodos acquireWakeLock() , decrementWakeLock() y clearWakeLock( ) en ril.cpp .

Escenario: solicitud RIL y respuesta asincrónica solicitada

En este escenario, si se espera que la respuesta solicitada por RIL demore un tiempo considerable (es decir, una respuesta a RIL_REQUEST_GET_AVAILABLE_NETWORKS ), el wakelock se mantiene durante mucho tiempo en el lado del procesador de la aplicación. Los problemas con el módem también pueden provocar una espera larga.

Figura 1. RIL solicitó respuesta asincrónica.

Solución 1: el módem mantiene el wakelock para la solicitud RIL y la respuesta asincrónica.

Figura 2. Wakelock retenido por módem.
  1. Se envía la solicitud RIL y el módem adquiere wakelock para procesar esa solicitud.
  2. El módem envía un reconocimiento que hace que el lado Java disminuya el contador de wakelock y lo libere cuando el valor del contador es 0.

    Nota: La duración del tiempo de espera de wakelock para la secuencia de confirmación de solicitud sería menor que la duración del tiempo de espera actualmente utilizado porque la confirmación debe recibirse con bastante rapidez.

  3. Después de procesar la solicitud, el módem envía una interrupción al código del proveedor que adquiere wakelock y envía una respuesta a ril.cpp, que a su vez adquiere wakelock y envía una respuesta al lado de Java.
  4. Cuando la respuesta llega al lado de Java, se adquiere wakelock y se devuelve una respuesta a la persona que llama.
  5. Después de que todos los módulos procesan la respuesta, el reconocimiento se envía (a través del socket) de regreso a ril.cpp , que luego libera el wakelock adquirido en el paso 3.

Solución 2: El módem no mantiene el wakelock y la respuesta es rápida (solicitud y respuesta RIL síncrona). El comportamiento sincrónico versus asincrónico está codificado para un comando RIL específico y se decide llamada por llamada.

Figura 3. Wakelock no retenido por el módem.
  1. La solicitud RIL se envía llamando a acquireWakeLock() en el lado de Java.
  2. El código de proveedor no necesita adquirir wakelock y puede procesar la solicitud y responder rápidamente.
  3. Cuando el lado de Java recibe la respuesta, se llama a decrementWakeLock() , lo que disminuye el contador de wakelock y libera el wakelock si el valor del contador es 0.

Escenario: respuesta no solicitada de RIL

En este escenario, las respuestas no solicitadas de RIL tienen un indicador de tipo de wakelock que indica si es necesario adquirir un wakelock para la respuesta del proveedor. Si se establece la bandera, se establece un wakelock cronometrado y la respuesta se envía a través de un socket al lado de Java. Cuando el temporizador expira, se libera el wakelock. El wakelock cronometrado podría ser demasiado largo o demasiado corto para diferentes respuestas no solicitadas de RIL.

Figura 4. Respuesta no solicitada de RIL.

Solución: se envía una confirmación desde el código Java al lado nativo ( ril.cpp ) en lugar de mantener un wakelock cronometrado en el lado nativo mientras se envía una respuesta no solicitada.

Figura 5. Usando ack en lugar de wakelock cronometrado.

Validando wakelocks rediseñados

Verifique que las llamadas RIL estén identificadas como sincrónicas o asincrónicas. Debido a que el consumo de energía de la batería puede depender del hardware/plataforma, los proveedores deben realizar algunas pruebas internas para determinar si el uso de la nueva semántica de wakelock para llamadas asincrónicas genera ahorros de energía de la batería.