Refactoring RIL

In Android 7.0 è stato eseguito il refactoring del Radio Interface Layer (RIL) utilizzando un insieme di funzionalità per migliorarne la funzionalità. Per implementare queste funzionalità, che sono facoltative, ma consigliate, sono necessarie modifiche al codice del partner. Le modifiche di refactoring sono compatibili con le versioni precedenti, pertanto le implementazioni precedenti delle funzionalità ristrutturate continueranno a funzionare.

Il refactoring di RIL include i seguenti miglioramenti:

  • Codici di errore RIL. Attiva codici di errore specifici oltre al codice GENERIC_FAILURE esistente. Questo aiuta a risolvere i problemi fornendo informazioni più specifiche sulla causa degli errori.
  • Controllo delle versioni RIL. Fornisce informazioni sulle versioni più accurate e facili da configurare.
  • Comunicazione RIL tramite wakelock. Migliora le prestazioni della batteria del dispositivo.

Puoi implementare uno o tutti i miglioramenti sopra indicati. Per maggiori dettagli, consulta i commenti del codice relativi al controllo delle versioni RIL in https://android.googlesource.com/platform/hardware/ril/+/main/include/telephony/ril.h.

Implementare i codici di errore RIL avanzati

Quasi tutte le chiamate di richiesta RIL possono restituire il codice di errore GENERIC_FAILURE in risposta a un errore. Si tratta di un problema relativo a tutte le risposte richieste fornite dagli OEM, che può rendere difficile il debug di un problema dalla segnalazione di bug se lo stesso codice di errore GENERIC_FAILURE viene restituito dalle chiamate RIL per motivi diversi. Per i fornitori può essere necessario molto tempo anche solo per identificare la parte del codice che potrebbe aver restituito un codice GENERIC_FAILURE.

In Android 7.x e versioni successive, gli OEM possono restituire un valore di codice di errore distinto associato a ogni errore diverso attualmente classificato come GENERIC_FAILURE. Gli OEM che non vogliono rivelare pubblicamente i propri codici di errore personalizzati possono restituire gli errori come un insieme distinto di numeri interi (ad esempio da 1 a x) mappati come OEM_ERROR_1 a OEM_ERROR_X. I fornitori devono assicurarsi che ogni codice di errore mascherato restituito corrisponda a un motivo di errore univoco nel codice. L'utilizzo di codici di errore specifici può velocizzare il debug RIL ogni volta che gli OEM restituiscono errori generici, poiché spesso può richiedere troppo tempo identificare la causa esatta di un codice di errore GENERIC_FAILURE (e talvolta è impossibile capirlo).

Inoltre, ril.h aggiunge altri codici di errore per gli enum RIL_LastCallFailCause e RIL_DataCallFailCause in modo che il codice del fornitore possa evitare di restituire errori generici come CALL_FAIL_ERROR_UNSPECIFIED e PDP_FAIL_ERROR_UNSPECIFIED.

Convalida i codici di errore RIL avanzati

Dopo aver aggiunto nuovi codici di errore per sostituire il codice GENERIC_FAILURE, verifica che i nuovi codici di errore vengano restituiti dalla chiamata RIL anziché da GENERIC_FAILURE.

Implementare il controllo delle versioni RIL avanzato

La gestione delle versioni RIL nelle release precedenti di Android era problematica: la versione stessa era imprecisa, il meccanismo per segnalare una versione RIL non era chiaro (inducendo alcuni fornitori a segnalare una versione errata) e la soluzione alternativa per stimare la versione era soggetta a inesattezze.

In Android 7.x e versioni successive, ril.h documenta tutti i valori della versione RIL, descrive la versione RIL corrispondente ed elenca tutte le modifiche per quella versione. Quando apportano modifiche corrispondenti a una versione RIL, i fornitori devono aggiornare la propria versione nel codice e restituirla in RIL_REGISTER.

Convalida il controllo delle versioni RIL avanzate

Verifica che la versione RIL corrispondente al tuo codice RIL venga restituita durante RIL_REGISTER (anziché RIL_VERSION definito in ril.h).

Implementa la comunicazione RIL utilizzando i wakelock

I wakelock temporizzati vengono utilizzati nella comunicazione RIL in modo impreciso, influendo negativamente sulle prestazioni della batteria. In Android 7.x e versioni successive, puoi migliorare le prestazioni classificando le richieste RIL e aggiornando il codice per gestire i wakelock in modo diverso per i diversi tipi di richieste.

Classificare le richieste RIL

Le richieste RIL possono essere richieste o non richieste. I fornitori devono inoltre classificare le richieste sollecitate come una delle seguenti:

  • sincrona. Richieste per le quali non è necessario molto tempo per rispondere. Ad esempio, RIL_REQUEST_GET_SIM_STATUS.
  • asincrona. Richieste che richiedono molto tempo per rispondere. Ad esempio, RIL_REQUEST_QUERY_AVAILABLE_NETWORKS.

Le richieste RIL richieste asincrone possono richiedere molto tempo. Dopo aver ricevuto un ack dal codice del fornitore, RIL Java rilascia il blocco di attivazione, il che potrebbe causare il passaggio dello stato del processore dell'app da inattivo a sospeso. Quando la risposta è disponibile nel codice del fornitore, RIL Java (l'elaboratore di app) acquisisce nuovamente il blocco di attivazione, elabora la risposta e torna allo stato inattivo. Questo passaggio da inattivo a sospensione e poi di nuovo a inattivo può consumare molta energia.

Se il tempo di risposta non è sufficientemente lungo, mantenere attivo il wakelock e rimanere in stato inattivo per tutto il tempo necessario per rispondere può essere più efficiente in termini di consumo energetico rispetto allo stato di sospensione, rilasciando il wakelock e riattivando il servizio quando arriva la risposta. I fornitori devono utilizzare misurazioni del consumo energetico specifiche della piattaforma per determinare il valore di soglia del tempo T in cui il consumo energetico in stato inattivo per l'intero tempo T è maggiore del consumo energetico durante il passaggio da inattivo a sospensione e di nuovo a inattivo nello stesso tempo T. Quando il tempo T è noto, i comandi RIL che richiedono più tempoT possono essere classificati come asincroni e i comandi rimanenti come sincronici.

Scenari di comunicazione RIL

I seguenti diagrammi illustrano scenari di comunicazione RIL comuni e forniscono soluzioni per la modifica del codice per gestire le richieste RIL richieste e non richieste.

Nota:per i dettagli sull'implementazione delle funzioni utilizzate nei seguenti diagrammi, consulta i metodi acquireWakeLock(), decrementWakeLock() e clearWakeLock( in ril.cpp.

Scenario: richiesta RIL e risposta asincrona richiesta

In questo scenario, se la risposta richiesta dall'RIL richiede molto tempo (ad es. una risposta aRIL_REQUEST_GET_AVAILABLE_NETWORKS), il blocco di attivazione viene mantenuto per molto tempo sul lato del processore dell'app. Anche i problemi del modem possono comportare un tempo di attesa molto lungo.

Figura 1. RIL ha richiesto una risposta asincrona.

Soluzione 1: il modem mantiene il wakelock per la richiesta RIL e la risposta asincrona.

Figura 2. Wakelock bloccato dal modem.
  1. La richiesta RIL viene inviata e il modem acquisisce il wakelock per elaborarla.
  2. Il modem invia un messaggio di conferma che fa sì che la parte Java diminuisca il contatore della modalità di attesa e lo rilasci quando il valore del contatore è 0.

    Nota: la durata del timeout di wakelock per la sequenza richiesta-ack è inferiore alla durata del timeout attualmente utilizzata perché l'ack dovrebbe essere ricevuto abbastanza rapidamente.

  3. Dopo aver elaborato la richiesta, il modem invia un'interruzione al codice del fornitore che acquisisce il blocco di attivazione e invia una risposta a ril.cpp, che a sua volta acquisisce il blocco di attivazione e invia una risposta al lato Java.
  4. Quando la risposta raggiunge il lato Java, viene acquisito il wakelock e viene restituita una risposta al chiamante.
  5. Dopo che la risposta è stata elaborata da tutti i moduli, il conferma viene inviata (tramite socket) a ril.cpp, che rilascia il blocco di riattivazione acquisito nel passaggio 3.

Soluzione 2: il modem non mantiene il blocco di attivazione e la risposta è rapida (richiesta e risposta RIL sincrone). Il comportamento sincrono rispetto a quello asincrono è hardcoded per un comando RIL specifico e deciso su base chiamata.

Figura 3. Wakelock non trattenuto dal modem.
  1. La richiesta RIL viene inviata chiamando acquireWakeLock() sul lato Java.
  2. Il codice del fornitore non deve acquisire il blocco di attivazione e può elaborare la richiesta e rispondere rapidamente.
  3. Quando la risposta viene ricevuta dal lato Java, viene chiamato decrementWakeLock(), che riduce il contatore wakelock e rilascia il wakelock se il valore del contatore è 0.

Scenario: risposta non richiesta da RIL

In questo scenario, le risposte non richieste dell'RIL hanno un flag di tipo wakelock che indica se è necessario acquisire un wakelock per la risposta del fornitore. Se il flag è impostato, viene impostato un blocco di attivazione temporizzato e la risposta viene inviata tramite un socket al lato Java. Alla scadenza del timer, il blocco attivazione viene rilasciato. Il blocco di attivazione temporizzato potrebbe essere troppo lungo o troppo breve per diverse risposte RIL non richieste.

Figura 4. Risposta non richiesta da RIL.

Soluzione: viene inviato un messaggio di conferma dal codice Java al lato nativo (ril.cpp) anziché mantenere un blocco di attivazione temporizzato sul lato nativo durante l'invio di una risposta non richiesta.

Figura 5. Utilizzo di ack anziché di blocco schermo temporizzato.

Convalida dei wakelock riprogettati

Verifica che le chiamate RIL siano identificate come sincrone o asincrone. Poiché il consumo della batteria può dipendere dall'hardware/dalla piattaforma, i fornitori devono eseguire alcuni test interni per scoprire se l'utilizzo della nuova semantica di wakelock per le chiamate asincrone consente di risparmiare batteria.