RIL-Refaktorierung

In Android 7.0 wurde die Radio Interface Layer (RIL) mit einer Reihe von Funktionen überarbeitet, um die RIL-Funktionalität zu verbessern. Zur Implementierung dieser Funktionen, die optional, aber empfehlenswert sind, sind Codeänderungen durch Partner erforderlich. Die Änderungen sind abwärtskompatibel, sodass frühere Implementierungen der überarbeiteten Funktionen weiterhin funktionieren.

Die RIL-Überarbeitung umfasst die folgenden Verbesserungen:

  • RIL-Fehlercodes : Zusätzlich zum vorhandenen GENERIC_FAILURE-Code werden spezifische Fehlercodes aktiviert. Dies erleichtert die Fehlerbehebung, da genauere Informationen zur Ursache von Fehlern bereitgestellt werden.
  • RIL-Versionsverwaltung : Bietet genauere und einfacher zu konfigurierende Versionsinformationen.
  • RIL-Kommunikation mit Wakelocks : Verbessert die Akkuleistung des Geräts.

Sie können eine oder alle der oben genannten Verbesserungen implementieren. Weitere Informationen finden Sie in den Codekommentaren zur RIL-Versionsverwaltung unter https://android.googlesource.com/platform/hardware/ril/+/android17-release/include/telephony/ril.h.

Erweiterte RIL-Fehlercodes implementieren

Fast alle RIL-Anfrageaufrufe können als Antwort auf einen Fehler den Fehlercode GENERIC_FAILURE zurückgeben. Dies ist ein Problem bei allen angeforderten Antworten, die von den OEMs zurückgegeben werden. Es kann schwierig sein, ein Problem anhand des Fehlerberichts zu beheben, wenn derselbe Fehlercode GENERIC_FAILURE aus verschiedenen Gründen von RIL-Aufrufen zurückgegeben wird. Es kann viel Zeit in Anspruch nehmen, bis Anbieter überhaupt feststellen, welcher Teil des Codes einen GENERIC_FAILURE-Code zurückgegeben haben könnte.

In Android 7.x und höher können OEMs einen eindeutigen Fehlercode für jeden Fehler zurückgeben, der derzeit als GENERIC_FAILURE kategorisiert ist. OEMs, die ihre benutzerdefinierten Fehlercodes nicht öffentlich preisgeben möchten, können Fehler als eindeutige Reihe von Ganzzahlen (z. B. 1 bis x) zurückgeben, die als OEM_ERROR_1 bis OEM_ERROR_X zugeordnet sind. Anbieter sollten darauf achten, dass jeder solche maskierte Fehlercode, der zurückgegeben wird, im Code einer eindeutigen Fehlerursache zugeordnet ist. Die Verwendung spezifischer Fehlercodes kann die RIL-Fehlerbehebung beschleunigen, wenn generische Fehler vom OEM zurückgegeben werden. Es kann oft zu viel Zeit in Anspruch nehmen, die genaue Ursache eines GENERIC_FAILURE-Fehlercodes zu ermitteln (und manchmal ist es unmöglich).

Außerdem werden in ril.h weitere Fehlercodes für die Enums RIL_LastCallFailCause und RIL_DataCallFailCause hinzugefügt, damit im Anbietercode keine generischen Fehler wie CALL_FAIL_ERROR_UNSPECIFIED und PDP_FAIL_ERROR_UNSPECIFIED zurückgegeben werden.

Erweiterte RIL-Fehlercodes validieren

Nachdem Sie neue Fehlercodes hinzugefügt haben, um den Code GENERIC_FAILURE zu ersetzen, prüfen Sie, ob die neuen Fehlercodes vom RIL-Aufruf anstelle von GENERIC_FAILURE zurückgegeben werden.

Erweiterte RIL-Versionsverwaltung implementieren

Die RIL-Versionsverwaltung in älteren Android-Versionen war problematisch: Die Version selbst war ungenau, der Mechanismus zum Melden einer RIL-Version war unklar (was dazu führte, dass einige Anbieter eine falsche Version meldeten) und die Problemumgehung zur Schätzung der Version war ungenau.

In Android 7.x und höher werden in ril.h alle RIL-Versionswerte dokumentiert, die entsprechende RIL-Version beschrieben und alle Änderungen für diese Version aufgeführt. Wenn Anbieter Änderungen vornehmen, die einer RIL-Version entsprechen, müssen sie ihre Version im Code aktualisieren und diese Version in RIL_REGISTER zurückgeben.

Erweiterte RIL-Versionsverwaltung validieren

Prüfen Sie, ob die RIL-Version, die Ihrem RIL-Code entspricht, während RIL_REGISTER zurückgegeben wird (und nicht die in ril.h definierte RIL_VERSION).

RIL-Kommunikation mit Wakelocks implementieren

Zeitgesteuerte Wakelocks werden in der RIL-Kommunikation ungenau verwendet, was sich negativ auf die Akkuleistung auswirkt. In Android 7.x und höher können Sie die Leistung verbessern, indem Sie RIL-Anfragen klassifizieren und den Code aktualisieren, um Wakelocks für verschiedene Anfragetypen unterschiedlich zu verarbeiten.

RIL-Anfragen klassifizieren

RIL-Anfragen können angefordert oder nicht angefordert sein. Anbieter sollten angeforderte Anfragen weiter als eine der folgenden klassifizieren:

  • Synchron : Anfragen, bei denen es nicht viel Zeit in Anspruch nimmt, eine Antwort zu senden. Beispiel: RIL_REQUEST_GET_SIM_STATUS.
  • Asynchron : Anfragen, bei denen es viel Zeit in Anspruch nimmt, eine Antwort zu senden. Beispiel: RIL_REQUEST_QUERY_AVAILABLE_NETWORKS.

Asynchrone angeforderte RIL-Anfragen können viel Zeit in Anspruch nehmen. Nachdem ein ACK vom Anbietercode empfangen wurde, gibt RIL Java den Wakelock frei, wodurch der App-Prozessor möglicherweise vom inaktiven in den Ruhezustand wechselt. Wenn die Antwort vom Anbietercode verfügbar ist, ruft RIL Java (der App-Prozessor) den Wakelock wieder ab, verarbeitet die Antwort und kehrt dann in den Leerlauf zurück. Ein solcher Wechsel vom Leerlauf in den Ruhezustand und wieder in den Leerlauf kann viel Strom verbrauchen.

Wenn die Antwortzeit nicht lang genug ist, kann es energieeffizienter sein, den Wakelock zu halten und während der gesamten Antwortzeit im Leerlauf zu bleiben, als in den Ruhezustand zu wechseln, indem der Wakelock freigegeben wird und das Gerät aufwacht, wenn die Antwort eintrifft. Anbieter sollten plattformspezifische Strommessungen verwenden, um den Schwellenwert für die Zeit T zu bestimmen, bei dem der Stromverbrauch durch den Leerlauf während der gesamten Zeit T höher ist als der Stromverbrauch durch den Wechsel vom Leerlauf in den Ruhezustand und wieder in den Leerlauf in derselben Zeit T. Wenn die Zeit T bekannt ist, können RIL-Befehle, die mehr als die Zeit T in Anspruch nehmen, als asynchron klassifiziert werden und die übrigen Befehle als synchron.

RIL-Kommunikationsszenarien

Die folgenden Diagramme veranschaulichen gängige RIL-Kommunikationsszenarien und bieten Lösungen zum Ändern des Codes, um angeforderte und nicht angeforderte RIL-Anfragen zu verarbeiten.

Hinweis: Implementierungsdetails zu den in den folgenden Diagrammen verwendeten Funktionen finden Sie in den Methoden acquireWakeLock(), decrementWakeLock() und clearWakeLock() in ril.cpp.

Szenario: RIL-Anfrage und angeforderte asynchrone Antwort

In diesem Szenario wird der Wakelock auf der Seite des App-Prozessors lange gehalten, wenn die angeforderte RIL-Antwort viel Zeit in Anspruch nimmt (d.h. eine Antwort auf RIL_REQUEST_GET_AVAILABLE_NETWORKS). Auch Modemprobleme können zu einer langen Wartezeit führen.

Abbildung 1 : Angeforderte asynchrone RIL-Antwort.

Lösung 1:Das Modem hält den Wakelock für die RIL-Anfrage und die asynchrone Antwort.

Abbildung 2 : Wakelock wird vom Modem gehalten.
  1. Die RIL-Anfrage wird gesendet und das Modem ruft den Wakelock ab, um diese Anfrage zu verarbeiten.
  2. Das Modem sendet eine Bestätigung, wodurch der Wakelock-Zähler auf der Java-Seite dekrementiert und freigegeben wird, wenn der Zählerwert 0 ist.

    Hinweis:Die Wakelock-Timeoutdauer für die Anfrage-ACK-Sequenz wäre kürzer als die derzeit verwendete Timeoutdauer, da die Bestätigung relativ schnell empfangen werden sollte.

  3. Nach der Verarbeitung der Anfrage sendet das Modem einen Interrupt an den Anbietercode, der den Wakelock abruft und eine Antwort an „ril.cpp“ sendet. Diese ruft wiederum den Wakelock ab und sendet eine Antwort an die Java-Seite.
  4. Wenn die Antwort auf der Java-Seite eintrifft, wird der Wakelock abgerufen und eine Antwort an den Aufrufer zurückgegeben.
  5. Nachdem die Antwort von allen Modulen verarbeitet wurde, wird eine Bestätigung (über einen Socket) an ril.cpp zurückgesendet, die dann den in Schritt 3 abgerufenen Wakelock freigibt.

Lösung 2:Das Modem hält den Wakelock nicht und die Antwort erfolgt schnell (synchrone RIL-Anfrage und -Antwort). Das synchrone oder asynchrone Verhalten ist für einen bestimmten RIL-Befehl fest codiert und wird für jeden Aufruf einzeln entschieden.

Abbildung 3. Wakelock wird nicht vom Modem gehalten.
  1. Die RIL-Anfrage wird gesendet, indem acquireWakeLock() auf der Java-Seite aufgerufen wird.
  2. Der Anbietercode muss den Wakelock nicht abrufen und kann die Anfrage schnell verarbeiten und beantworten.
  3. Wenn die Antwort auf der Java-Seite empfangen wird, wird decrementWakeLock() aufgerufen, wodurch der Wakelock-Zähler dekrementiert und der Wakelock freigegeben wird, wenn der Zählerwert 0 ist.

Szenario: Nicht angeforderte RIL-Antwort

In diesem Szenario haben nicht angeforderte RIL-Antworten ein Wakelock-Typ-Flag in der , das angibt, ob ein Wakelock für die Anbieterantwort abgerufen werden muss. Wenn das Flag gesetzt ist, wird ein zeitgesteuerter Wakelock festgelegt und die Antwort über einen Socket an die Java-Seite gesendet. Wenn der Timer abläuft, wird der Wakelock freigegeben. Der zeitgesteuerte Wakelock kann für verschiedene nicht angeforderte RIL-Antworten zu lang oder zu kurz sein.

Abbildung 4. Nicht angeforderte RIL-Antwort.

Lösung:Statt einen zeitgesteuerten Wakelock auf der nativen Seite zu halten, während eine nicht angeforderte Antwort gesendet wird, wird eine Bestätigung vom Java-Code an die native Seite (ril.cpp) gesendet.

Abbildung 5 Bestätigung statt zeitgesteuertem Wakelock verwenden.

Überarbeitete Wakelocks validieren

Prüfen Sie, ob RIL-Aufrufe als synchron oder asynchron identifiziert werden. Da der Akkuverbrauch von der Hardware/Plattform abhängen kann, sollten Anbieter einige interne Tests durchführen, um herauszufinden, ob die Verwendung der neuen Wakelock-Semantik für asynchrone Aufrufe zu einer Einsparung von Akkustrom führt.