Refatoração RIL

O Android 7.0 refatorizou a camada de interface de rádio (RIL, na sigla em inglês) usando um conjunto de recursos para melhorar a funcionalidade da RIL. As mudanças no código do parceiro são necessárias para implementar esses recursos, que são opcionais, mas recomendados. As mudanças de refatoração são compatíveis com versões anteriores, portanto as implementações anteriores dos recursos refatorados continuam funcionando.

A refatoração do RIL inclui as seguintes melhorias:

  • Códigos de erro do RIL. Ativa códigos de erro específicos além do código GENERIC_FAILURE. Isso ajuda na solução de problemas, fornecendo informações mais específicas sobre a causa dos erros.
  • Controle de versões do RIL. Fornece informações de versão mais precisas e fáceis de configurar.
  • Comunicação RIL usando wakelocks. Melhora o desempenho da bateria do dispositivo.

Você pode implementar todas as melhorias acima. Para mais detalhes, consulte os comentários de código sobre o controle de versões do RIL em https://android.googlesource.com/platform/hardware/ril/+/main/include/telephony/ril.h.

Implementar códigos de erro aprimorados do RIL

Quase todas as chamadas de solicitação de RIL podem retornar o código de erro GENERIC_FAILURE em resposta a um erro. Esse é um problema com todas as respostas solicitadas retornadas pelos OEMs, o que pode dificultar a depuração de um problema no relatório de bug se o mesmo código de erro GENERIC_FAILURE for retornado por chamadas RIL por motivos diferentes. Pode levar um tempo considerável para que os fornecedores identifiquem qual parte do código poderia ter retornado um código GENERIC_FAILURE.

No Android 7.x e versões mais recentes, os OEMs podem retornar um valor de código de erro distinto associado a cada erro diferente que está atualmente categorizado como GENERIC_FAILURE. OEMs que não querem revelar publicamente os códigos de erro personalizados podem retornar erros como um conjunto distinto de números inteiros (como 1 a x) mapeados como OEM_ERROR_1 a OEM_ERROR_X. Os fornecedores precisam garantir que cada código de erro mascarado retornado seja mapeado para um motivo de erro exclusivo no código. O uso de códigos de erro específicos pode acelerar a depuração do RIL sempre que erros genéricos são retornados pelo OEM, já que muitas vezes leva muito tempo para identificar a causa exata de um código de erro GENERIC_FAILURE. Às vezes, isso é impossível.

Além disso, ril.h adiciona mais códigos de erro para os tipos enumerados RIL_LastCallFailCause e RIL_DataCallFailCause para que o código do fornecedor possa evitar o retorno de erros genéricos, como CALL_FAIL_ERROR_UNSPECIFIED e PDP_FAIL_ERROR_UNSPECIFIED.

Validar códigos de erro aprimorados do RIL

Depois de adicionar novos códigos de erro para substituir o código GENERIC_FAILURE, verifique se os novos códigos de erro são retornados pela chamada RIL em vez de GENERIC_FAILURE.

Implementar o controle de versões aprimorado do RIL

A versão do RIL em versões mais antigas do Android era problemática: a versão era imprecisa, o mecanismo para informar uma versão do RIL não era claro (o que fazia alguns fornecedores informar uma versão incorreta) e a solução alternativa para estimar a versão era propensa a imprecisões.

No Android 7.x e mais recentes, o ril.h documenta todos os valores da versão do RIL, descreve a versão do RIL correspondente e lista todas as mudanças para essa versão. Ao fazer mudanças que correspondem a uma versão do RIL, os fornecedores precisam atualizar a versão no código e retornar essa versão no RIL_REGISTER.

Validar a versão do RIL otimizado

Verifique se a versão do RIL correspondente ao seu código é retornada durante RIL_REGISTER (em vez da RIL_VERSION definida em ril.h).

Implementar a comunicação RIL usando wakelocks

Os wakelocks programados são usados na comunicação do RIL de maneira imprecisa, o que afeta negativamente o desempenho da bateria. No Android 7.x e versões mais recentes, é possível melhorar o desempenho classificando solicitações de RIL e atualizando o código para processar wakelocks de maneira diferente para diferentes tipos de solicitação.

Classificar solicitações de RIL

As solicitações de RIL podem ser solicitadas ou não solicitadas. Os fornecedores precisam classificar as solicitações solicitadas como uma das seguintes opções:

  • síncrona. Solicitações que não levam um tempo considerável para responder. Por exemplo, RIL_REQUEST_GET_SIM_STATUS.
  • assíncrona. Solicitações que levam um tempo considerável para responder. Por exemplo, RIL_REQUEST_QUERY_AVAILABLE_NETWORKS.

As solicitações RIL solicitadas assíncronas podem levar um tempo considerável. Depois de receber um ack do código do fornecedor, o RIL Java libera o wakelock, o que pode fazer com que o processador do app passe do estado inativo para o suspenso. Quando a resposta está disponível no código do fornecedor, o RIL Java (o processador do app) adquire o wakelock novamente, processa a resposta e retorna ao modo inativo. Essa mudança de inatividade para suspensão e de volta para inatividade pode consumir muita energia.

Se o tempo de resposta não for longo o suficiente, manter o wakelock e ficar em modo inativo durante todo o tempo que leva para responder pode ser mais eficiente em termos de energia do que entrar no estado de suspensão liberando o wakelock e ativando quando a resposta chegar. Os fornecedores precisam usar medições de energia específicas da plataforma para determinar o valor de limite do tempo T quando a energia consumida ao ficar ocioso durante todo o tempo T for maior do que a energia consumida ao passar de ocioso para suspenso e para ocioso no mesmo tempo T. Quando o tempo T é conhecido, os comandos RIL que levam mais tempo que T podem ser classificados como assíncronos e os comandos restantes como síncronos.

Cenários de comunicação do RIL

Os diagramas a seguir ilustram cenários comuns de comunicação do RIL e fornecem soluções para modificar o código e processar solicitações solicitadas e não solicitadas do RIL.

Observação:para detalhes de implementação sobre as funções usadas nos diagramas a seguir, consulte os métodos acquireWakeLock(), decrementWakeLock() e clearWakeLock( em ril.cpp.

Cenário: solicitação RIL e resposta assíncrona solicitada

Nesse cenário, se a resposta solicitada pelo RIL for esperada por considerável tempo (por exemplo, uma resposta a RIL_REQUEST_GET_AVAILABLE_NETWORKS), o wakelock será mantido por um longo período no processador do app. Problemas com o modem também podem resultar em uma espera longa.

Figura 1. O RIL solicitou uma resposta assíncrona.

Solução 1:o modem mantém o wakelock para a solicitação do RIL e a resposta assíncrona.

Figura 2. Wakelock mantido pelo modem.
  1. A solicitação RIL é enviada e o modem adquire wakelock para processar essa solicitação.
  2. O modem envia um aviso que faz com que o lado Java diminua o contador de wakelock e o libere quando o valor do contador for 0.

    Observação:a duração do tempo limite de wakelock para a sequência de solicitação-ACK será menor do que a duração do tempo limite usado atualmente, porque o ACK precisa ser recebido rapidamente.

  3. Depois de processar a solicitação, o modem envia uma interrupção para o código do fornecedor que adquire o wakelock e envia uma resposta para ril.cpp, que, por sua vez, adquire o wakelock e envia uma resposta para o lado Java.
  4. Quando a resposta chega ao lado Java, o wakelock é adquirido e uma resposta é retornada ao autor da chamada.
  5. Depois que a resposta é processada por todos os módulos, o reconhecimento é enviado (via soquete) de volta para ril.cpp, que libera o wakelock adquirido na etapa 3.

Solução 2:o modem não mantém o wakelock, e a resposta é rápida (sincronia de solicitação e resposta do RIL). O comportamento síncrono e assíncrono é codificado para um comando RIL específico e decidido chamada por chamada.

Figura 3. Wakelock não mantido pelo modem.
  1. A solicitação RIL é enviada chamando acquireWakeLock() no lado Java.
  2. O código do fornecedor não precisa adquirir o wakelock e pode processar a solicitação e responder rapidamente.
  3. Quando a resposta é recebida pelo lado Java, decrementWakeLock() é chamada, o que diminui o contador de wakelock e libera o wakelock se o valor do contador for 0.

Cenário: resposta não solicitada do RIL

Nesse cenário, as respostas não solicitadas do RIL têm uma flag do tipo wakelock que indica se um wakelock precisa ser adquirido para a resposta do fornecedor. Se a flag estiver definida, um wakelock cronometrado será definido e a resposta será enviada por um socket para o lado Java. Quando o timer expira, o wakelock é liberado. O wakelock programado pode ser muito longo ou muito curto para diferentes respostas não solicitadas do RIL.

Figura 4. Resposta não solicitada do RIL.

Solução:um aviso é enviado do código Java para o lado nativo (ril.cpp) em vez de manter um wakelock programado no lado nativo ao enviar uma resposta não solicitada.

Figura 5. Usar ACK em vez de wakelock programado.

Validar wakelocks redesenhados

Verifique se as chamadas RIL são identificadas como síncronas ou assíncronas. Como o consumo de energia da bateria pode depender do hardware/plataforma, os fornecedores precisam fazer alguns testes internos para descobrir se o uso da nova semântica de wakelock para chamadas assíncronas leva à economia de energia da bateria.