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 RIL. São necessárias alterações no código do parceiro 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 funcionando.

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 erros, fornecendo informações mais específicas sobre a causa dos erros.
  • Versionamento 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 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 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 os fornecedores identificarem que parte do código poderia ter retornado um código GENERIC_FAILURE .

No Android 7.x e versões posteriores, 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 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 .

Implementando versionamento RIL aprimorado

O controle de versão RIL em versões mais antigas do Android era problemático: 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 correspondam 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 comunicação RIL usando wakelocks

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

Classificando solicitações RIL

As solicitações RIL podem ser solicitadas ou não solicitadas. Os fornecedores devem classificar ainda 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 serem respondidas. Por exemplo, RIL_REQUEST_QUERY_AVAILABLE_NETWORKS .

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 inativo 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 modo inativo. Essa mudança de inativo para suspenso e para inativo pode consumir muita energia.

Se o tempo de resposta não for longo o suficiente, segurar 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 potência específicas da plataforma para determinar o valor limite do tempo T quando a energia consumida ao permanecer ocioso durante todo o tempo T for maior que a energia consumida ao passar do modo inativo para a suspensão e para o modo inativo 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 comandos restantes 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.

Nota: Para obter detalhes de implementação sobre 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 RIL levar um tempo considerável (ou seja, uma resposta para RIL_REQUEST_GET_AVAILABLE_NETWORKS ), o wakelock será 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 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 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 confirmação de solicitação seria menor que a duração do tempo limite usado atualmente porque a confirmação deve ser recebida com bastante rapidez.

  3. Após processar a solicitação, o modem envia uma interrupção ao 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 chamador.
  5. Após a resposta ser processada por todos os módulos, a confirmação é enviada (via soquete) 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íncrona). O comportamento síncrono versus 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() é 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

Neste cenário, as respostas não solicitadas 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 meio de um soquete para o lado Java. Quando o cronômetro expirar, o wakelock será liberado. O wakelock cronometrado pode ser muito longo ou muito curto para diferentes respostas RIL não solicitadas.

Figura 4. Resposta não solicitada do 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 redesenhados

Verifique se as chamadas RIL estã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 wakelock para chamadas assíncronas leva à economia de energia da bateria.