Refatoração RIL

O Android 7.0 refatorou a camada de interface de rádio (RIL) usando um conjunto de recursos para melhorar a funcionalidade do RIL. As 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. Habilita códigos de erro específicos além do código GENERIC_FAILURE existente. Isso ajuda na solução de problemas de erros 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/+/master/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 os fornecedores até mesmo identificarem qual parte do código pode 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 para OEM_ERROR_X . Os fornecedores devem garantir que cada código de erro mascarado retornado mapeie para um motivo de erro exclusivo no código. O uso de códigos de erro específicos pode acelerar a depuração RIL sempre que erros genéricos são retornados pelo OEM, pois muitas vezes 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 enumerações 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 .

Implementação de versão aprimorada de RIL

O versionamento de RIL em versões mais antigas do Android era problemático: a própria versão 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 para essa versão. Ao fazer alterações que correspondam a uma versão RIL, os fornecedores devem atualizar sua versão em código e retornar essa versão em RIL_REGISTER .

Validando o versionamento de RIL aprimorado

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

Implementando a comunicação RIL usando wakelocks

Wakelocks temporizados são utilizados 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 solicitações RIL e atualizando o código para lidar com wakelocks de maneira diferente para diferentes tipos de solicitação.

Classificação de solicitações RIL

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

  • síncrono . Solicitações que não levam um tempo considerável para responder. 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. Após 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 o estado 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 estado inativo. Essa mudança de inativo para suspender 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 em termos de energia do que entrar no estado de suspensão liberando o wakelock e acordando 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 permanecendo inativo por todo o tempo T é maior do que a energia consumida movendo-se de inativa para suspensão e para inativa no mesmo tempo T . Quando o tempo T é conhecido, os comandos RIL que demoram mais 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 de implementação das funções usadas nos diagramas a seguir, consulte os acquireWakeLock() , decrementWakeLock() e clearWakeLock( ) em ril.cpp .

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

Nesse cenário, se espera-se que a resposta solicitada por RIL leve um tempo considerável (ou seja, uma resposta a 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.

    Observação: a duração do tempo limite do wakelock para a sequência de solicitação de confirmação seria menor do que a duração do tempo limite usada atualmente, pois a confirmação deve ser recebida com bastante rapidez.

  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 chamador.
  5. Após a resposta ser processada por todos os módulos, a confirmação é enviada (via socket) de volta para ril.cpp , que então libera o wakelock adquirido na etapa 3.

Solução 2: O modem não mantém o wakelock e a resposta é rápida (solicitação e resposta síncrona de RIL). O comportamento síncrono versus assíncrono é codificado para um comando RIL específico e decidido em uma base de 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() é 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 RIL

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

Figura 4. Resposta não solicitada RIL.

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

Figura 5. Usando ack em vez de wakelock temporizado.

Validando wakelocks redesenhados

Verifique se as chamadas RIL são identificadas como síncronas ou assíncronas. Como o consumo de energia da bateria pode ser dependente de 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.