Refatoração RIL

O Android 7.0 refatorou a Radio Interface Layer (RIL) usando um conjunto de recursos para melhorar a funcionalidade RIL. Alterações no código do parceiro são necessárias para implementar esses recursos, que são opcionais, mas incentivados. As alterações de refatoração são compatíveis com versões anteriores, portanto, as implementações anteriores dos recursos refatorados continuam a funcionar.

A refatoração RIL inclui as seguintes melhorias:

  • Códigos de erro RIL. Ativa códigos de erro específicos além do código GENERIC_FAILURE existente. Isso ajuda na solução de problemas de erro, fornecendo informações mais específicas sobre a causa dos erros.
  • Versão 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 qualquer uma ou todas as melhorias acima. Para obter mais detalhes, consulte os comentários de código sobre o controle de versão RIL em https://android.googlesource.com/platform/hardware/ril/+/main/include/telephony/ril.h .

Implementando códigos de erro RIL aprimorados

Quase todas as chamadas de solicitação RIL podem retornar o código de erro GENERIC_FAILURE em resposta a um erro. Este é um problema com todas as respostas solicitadas retornadas pelos OEMs, o que pode dificultar a depuração de um problema do 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.xe superior, os OEMs podem retornar um valor de código de erro distinto associado a cada erro diferente atualmente categorizado como GENERIC_FAILURE . Os OEMs que não desejam revelar publicamente seus 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 devem garantir que cada código de erro mascarado retorne mapas 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, pois geralmente pode levar muito tempo para identificar a causa exata de um código de erro GENERIC_FAILURE (e às vezes é impossível descobrir).

Além disso, ril.h adiciona mais códigos de erro para as enums 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 .

Validando códigos de erro RIL aprimorados

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 .

Implementando versões aprimoradas de RIL

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

No Android 7.xe superior, ril.h documenta todos os valores de versão RIL, descreve a versão RIL correspondente e lista todas as alterações dessa versão. Ao fazer alterações que correspondem a uma versão RIL, os fornecedores devem atualizar sua versão no código e retornar essa versão em RIL_REGISTER .

Validando o versionamento RIL aprimorado

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

Implementando a comunicação RIL usando wakelocks

Wakelocks temporizados são usados ​​na comunicação RIL de forma imprecisa, o que afeta negativamente o desempenho da bateria. No Android 7.xe superior, você pode melhorar o desempenho classificando as solicitações RIL e atualizando o código para lidar com wakelocks de maneira diferente para diferentes tipos de solicitação.

Classificando solicitações de RIL

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

  • síncrono . Solicitações que não levam muito tempo para serem respondidas. Por exemplo, RIL_REQUEST_GET_SIM_STATUS .
  • assíncrono . 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 uma confirmação do código do fornecedor, o RIL Java libera o wakelock, o que pode fazer com que o processador do aplicativo passe do estado ocioso para suspenso. Quando a resposta está disponível no código do fornecedor, o RIL Java (o processador do aplicativo) readquire o wakelock, processa a resposta e retorna ao modo inativo. Essa mudança de inativo para suspenso para inativo pode consumir muita energia.

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

Cenários de comunicação RIL

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

Observação: para obter detalhes sobre a implementação das 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 for esperado que a resposta solicitada por RIL leve um tempo considerável (ou seja, uma resposta para RIL_REQUEST_GET_AVAILABLE_NETWORKS ), o wakelock é mantido por um longo tempo no lado do processador do aplicativo. Problemas de modem também podem resultar em uma longa espera.

Figura 1. Resposta assíncrona solicitada por RIL.

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

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

    Nota: A duração do tempo limite do wakelock para a sequência de solicitação-reconhecimento seria menor do que a duração do tempo limite usado atualmente porque o ACK deve 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 atinge o lado Java, o wakelock é adquirido e uma resposta é retornada ao responsável pela chamada.
  5. Depois que a resposta é processada por todos os módulos, o reconhecimento é enviado (via socket) de volta para ril.cpp , que então libera o wakelock adquirido na etapa 3.

Solução 2: O modem não segura o wakelock e a resposta é rápida (solicitação e resposta RIL síncronas). O comportamento síncrono versus assíncrono é codificado permanentemente para um comando RIL específico e decidido chamada por chamada.

Figura 3. Wakelock não mantido pelo modem.
  1. A requisição RIL é enviada por meio de uma chamada 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() é chamado, o que diminui o contador de wakelock e libera o wakelock se o valor do contador for 0.

Cenário: resposta não solicitada de RIL

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

Figura 4. Resposta não solicitada de RIL.

Solução: Uma confirmação é enviada do código Java para o lado nativo ( ril.cpp ) em vez de manter um wakelock cronometrado no lado nativo enquanto envia uma resposta não solicitada.

Figura 5. Usando ack em vez de wakelock cronometrado.

Validando wakelocks reprojetados

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 devem 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.