Refactoring RIL

Android 7.0 ha effettuato il refactoring del Radio Interface Layer (RIL) utilizzando una serie di funzionalità per migliorare la funzionalità RIL. Per implementare queste funzionalità sono necessarie modifiche al codice partner, che sono facoltative ma incoraggiate. Le modifiche al refactoring sono compatibili con le versioni precedenti, quindi le implementazioni precedenti delle funzionalità di refactoring continuano a funzionare.

Il refactoring RIL include i seguenti miglioramenti:

  • Codici di errore RIL. Abilita codici di errore specifici oltre al codice GENERIC_FAILURE esistente. Ciò agevola la risoluzione dei problemi fornendo informazioni più specifiche sulla causa degli errori.
  • Versioni RIL. Fornisce informazioni sulla versione più precise e più facili da configurare.
  • Comunicazione RIL utilizzando wakelock. Migliora le prestazioni della batteria del dispositivo.

È possibile implementare uno o tutti i miglioramenti di cui sopra. Per ulteriori dettagli, fare riferimento ai commenti sul codice sul controllo delle versioni RIL in https://android.googlesource.com/platform/hardware/ril/+/main/include/telephony/ril.h .

Implementazione di 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. Questo è un problema con tutte le risposte sollecitate restituite 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. Può essere necessario molto tempo prima che i fornitori identifichino quale parte del codice potrebbe aver restituito un codice GENERIC_FAILURE .

In Android 7.x e versioni successive, gli OEM possono restituire un valore del codice di errore distinto associato a ciascun errore diverso attualmente classificato come GENERIC_FAILURE . Gli OEM che non desiderano 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 da OEM_ERROR_1 a OEM_ERROR_X . I fornitori devono garantire che ciascuno di questi codici di errore mascherato restituisca le mappe per un motivo di errore univoco nel codice. L'uso di codici di errore specifici può velocizzare il debug RIL ogni volta che l'OEM restituisce errori generici, poiché spesso può essere necessario troppo tempo per identificare la causa esatta di un codice di errore GENERIC_FAILURE (e talvolta è impossibile capirlo).

Inoltre, ril.h aggiunge più codici di errore per le enumerazioni 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 dei codici di errore RIL avanzati

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

Implementazione del controllo delle versioni RIL avanzato

Il controllo delle versioni RIL nelle versioni Android precedenti era problematico: 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 imprecisioni.

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 tale versione. Quando si apportano modifiche che corrispondono a una versione RIL, i fornitori devono aggiornare la propria versione nel codice e restituire tale versione in RIL_REGISTER .

Convalida del controllo delle versioni RIL avanzato

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

Implementazione della comunicazione RIL utilizzando wakelock

I wakelock temporizzati vengono utilizzati nella comunicazione RIL in modo impreciso, il che influisce 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 richiesta.

Classificazione delle richieste RIL

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

  • sincrono . Richieste che non richiedono molto tempo per rispondere. Ad esempio, RIL_REQUEST_GET_SIM_STATUS .
  • asincrono . Richieste che richiedono molto tempo per rispondere. Ad esempio, RIL_REQUEST_QUERY_AVAILABLE_NETWORKS .

Le richieste RIL sollecitate asincrone possono richiedere molto tempo. Dopo aver ricevuto un riconoscimento dal codice del fornitore, RIL Java rilascia il wakelock, che potrebbe far sì che il processore dell'applicazione passi dallo stato inattivo allo stato di sospensione. Quando la risposta è disponibile dal codice del fornitore, RIL Java (il processore dell'applicazione) riacquisisce il wakelock, elabora la risposta, quindi torna allo stato inattivo. Questo passaggio dal minimo alla sospensione al minimo può consumare molta energia.

Se il tempo di risposta non è sufficientemente lungo, tenere premuto il wakelock e rimanere inattivo per tutto il tempo necessario per rispondere può essere più efficiente dal punto di vista energetico rispetto all'entrata in stato di sospensione rilasciando il wakelock e riattivandosi quando arriva la risposta. I fornitori dovrebbero utilizzare misurazioni di potenza specifiche della piattaforma per determinare il valore di soglia del tempo T quando la potenza consumata rimanendo inattivo per l'intero tempo T è maggiore della potenza consumata passando dal minimo alla sospensione e al minimo nello stesso tempo T Quando il tempo T è noto, i comandi RIL che richiedono più del tempo T possono essere classificati come asincroni e i restanti comandi classificati come sincroni.

Scenari di comunicazione RIL

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

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

Scenario: richiesta RIL e risposta asincrona sollecitata

In questo scenario, se si prevede che la risposta sollecitata da RIL richieda molto tempo (ad esempio una risposta a RIL_REQUEST_GET_AVAILABLE_NETWORKS ), il wakelock viene mantenuto a lungo sul lato del processore dell'applicazione. Anche i problemi del modem possono comportare una lunga attesa.

Figura 1. RIL ha sollecitato la risposta asincrona.

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

Figura 2. Wakelock mantenuto dal modem.
  1. La richiesta RIL viene inviata e il modem acquisisce il wakelock per elaborare tale richiesta.
  2. Il modem invia un riconoscimento che fa sì che il lato Java decrementi il ​​contatore wakelock e lo rilasci quando il valore del contatore è 0.

    Nota: la durata del timeout del wakelock per la sequenza richiesta-riconoscimento sarebbe inferiore alla durata del timeout attualmente utilizzata poiché il riconoscimento dovrebbe essere ricevuto abbastanza rapidamente.

  3. Dopo aver elaborato la richiesta, il modem invia un interrupt al codice del fornitore che acquisisce wakelock e invia una risposta a ril.cpp, che a sua volta acquisisce wakelock 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 riconoscimento viene inviato (tramite socket) a ril.cpp , che quindi rilascia il wakelock acquisito nel passaggio 3.

Soluzione 2: il modem non mantiene il wakelock e la risposta è rapida (richiesta e risposta RIL sincrone). Il comportamento sincrono e asincrono è codificato per un comando RIL specifico e deciso call-by-callbasis.

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

Scenario: risposta non richiesta RIL

In questo scenario, le risposte RIL non richieste 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 wakelock temporizzato e la risposta viene inviata tramite un socket al lato Java. Quando il timer scade, il wakelock viene rilasciato. Il wakelock temporizzato potrebbe essere troppo lungo o troppo breve per le diverse risposte RIL non richieste.

Figura 4. Risposta non richiesta RIL.

Soluzione: viene inviato un riconoscimento dal codice Java al lato nativo ( ril.cpp ) invece di mantenere un wakelock temporizzato sul lato nativo durante l'invio di una risposta non richiesta.

Figura 5. Utilizzo di ack invece del wakelock temporizzato.

Convalida dei wakelock riprogettati

Verificare che le chiamate RIL siano identificate come sincrone o asincrone. Poiché il consumo energetico della batteria può dipendere dall'hardware/piattaforma, i fornitori dovrebbero eseguire alcuni test interni per scoprire se l'utilizzo della nuova semantica wakelock per le chiamate asincrone porta a un risparmio energetico della batteria.