RIL-Refactoring

Android 7.0 hat den Radio Interface Layer (RIL) mithilfe einer Reihe von Funktionen überarbeitet, um die RIL-Funktionalität zu verbessern. Zur Implementierung dieser Funktionen sind Änderungen am Partnercode erforderlich. Diese sind optional, werden aber empfohlen. Refactoring-Änderungen sind abwärtskompatibel, sodass frühere Implementierungen der Refactoring-Funktionen weiterhin funktionieren.

Das RIL-Refactoring umfasst die folgenden Verbesserungen:

  • RIL-Fehlercodes. Aktiviert spezifische Fehlercodes zusätzlich zum vorhandenen GENERIC_FAILURE Code. Dies hilft bei der Fehlerbehebung, indem es genauere Informationen über die Fehlerursache liefert.
  • RIL-Versionierung. Bietet genauere und einfacher zu konfigurierende Versionsinformationen.
  • RIL-Kommunikation mit Wakelocks. Verbessert die Akkuleistung des Geräts.

Sie können einige oder alle der oben genannten Verbesserungen implementieren. Weitere Einzelheiten finden Sie in den Codekommentaren zur RIL-Versionierung unter https://android.googlesource.com/platform/hardware/ril/+/main/include/telephony/ril.h .

Implementierung erweiterter RIL-Fehlercodes

Fast alle RIL-Anforderungsaufrufe können als Reaktion auf einen Fehler den Fehlercode GENERIC_FAILURE zurückgeben. Dies ist ein Problem bei allen angeforderten Antworten, die von den OEMs zurückgegeben werden, was es schwierig machen kann, ein Problem anhand des Fehlerberichts zu beheben, wenn derselbe GENERIC_FAILURE Fehlercode aus unterschiedlichen Gründen von RIL-Aufrufen zurückgegeben wird. Es kann lange dauern, bis Anbieter überhaupt erkennen, 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 Fehlercodewert zurückgeben, der jedem einzelnen Fehler zugeordnet ist, der derzeit als GENERIC_FAILURE kategorisiert ist. OEMs, die ihre benutzerdefinierten Fehlercodes nicht öffentlich preisgeben möchten, können Fehler als eindeutigen Satz von Ganzzahlen (z. B. 1 bis x) zurückgeben, der als OEM_ERROR_1 bis OEM_ERROR_X zugeordnet ist. Anbieter sollten sicherstellen, dass jeder dieser maskierten Fehlercodes einer eindeutigen Fehlerursache im Code zugeordnet ist. Die Verwendung spezifischer Fehlercodes kann das RIL-Debugging beschleunigen, wenn generische Fehler vom OEM zurückgegeben werden, da es oft zu lange dauert, die genaue Ursache eines GENERIC_FAILURE Fehlercodes zu identifizieren (und manchmal ist es unmöglich, sie herauszufinden).

Darüber hinaus fügt ril.h weitere Fehlercodes für die Aufzählungen RIL_LastCallFailCause und RIL_DataCallFailCause hinzu, sodass Herstellercode die Rückgabe allgemeiner Fehler wie CALL_FAIL_ERROR_UNSPECIFIED und PDP_FAIL_ERROR_UNSPECIFIED vermeiden kann.

Validierung erweiterter RIL-Fehlercodes

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

Implementierung einer erweiterten RIL-Versionierung

Die RIL-Versionierung in älteren Android-Versionen war problematisch: Die Version selbst war ungenau, der Mechanismus zur Meldung 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 anfällig für Ungenauigkeiten.

In Android 7.x und höher dokumentiert ril.h alle RIL-Versionswerte, beschreibt die entsprechende RIL-Version und listet alle Änderungen für diese Version auf. 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.

Validierung der erweiterten RIL-Versionierung

Stellen Sie sicher, dass die Ihrem RIL-Code entsprechende RIL-Version während RIL_REGISTER zurückgegeben wird (und nicht die in ril.h definierte RIL_VERSION ).

Implementierung der RIL-Kommunikation mithilfe von Wakelocks

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

RIL-Anfragen klassifizieren

RIL-Anfragen können entweder erbeten oder unaufgefordert erfolgen. Anbieter sollten angeforderte Anfragen außerdem als eine der folgenden Kategorien klassifizieren:

  • synchron . Anfragen, deren Beantwortung nicht viel Zeit in Anspruch nimmt. Zum Beispiel RIL_REQUEST_GET_SIM_STATUS .
  • asynchron . Anfragen, deren Beantwortung viel Zeit in Anspruch nimmt. Zum Beispiel RIL_REQUEST_QUERY_AVAILABLE_NETWORKS .

Asynchron angeforderte RIL-Anfragen können viel Zeit in Anspruch nehmen. Nach Erhalt einer Bestätigung vom Herstellercode gibt RIL Java den Wakelock frei, was dazu führen kann, dass der Anwendungsprozessor vom Ruhezustand in den Suspend-Zustand wechselt. Wenn die Antwort im Code des Anbieters verfügbar ist, erhält RIL Java (der Anwendungsprozessor) den Wakelock erneut, verarbeitet die Antwort und kehrt dann in den Leerlauf zurück. Ein solcher Wechsel vom Leerlauf zum Suspendieren zum Leerlauf kann viel Strom verbrauchen.

Wenn die Antwortzeit nicht lang genug ist, kann es energieeffizienter sein, den Wakelock aufrechtzuerhalten und über die gesamte Reaktionszeit im Leerlauf zu bleiben, als in den Suspend-Zustand zu wechseln, indem man den Wakelock aufhebt und aufwacht, wenn die Antwort eintrifft. Anbieter sollten plattformspezifische Leistungsmessungen verwenden, um den Schwellenwert der Zeit T zu bestimmen, wenn die durch das Verbleiben im Leerlauf über die gesamte Zeit T verbrauchte Leistung größer ist als die Leistung, die durch den Wechsel vom Leerlauf in den Ruhezustand und in den Leerlauf in derselben Zeit T verbraucht wird. Wenn die Zeit T bekannt ist, können RIL-Befehle, die mehr als die Zeit T benötigen, als asynchron und die übrigen Befehle als synchron klassifiziert werden.

RIL-Kommunikationsszenarien

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

Hinweis: Einzelheiten zur Implementierung der 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

Wenn in diesem Szenario erwartet wird, dass die von RIL angeforderte Antwort beträchtliche Zeit in Anspruch nimmt (z. B. eine Antwort auf RIL_REQUEST_GET_AVAILABLE_NETWORKS ), wird der Wakelock auf der Seite des Anwendungsprozessors lange gehalten. Auch Modemprobleme können zu langen Wartezeiten führen.

Abbildung 1. RIL hat eine asynchrone Antwort angefordert.

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

Abbildung 2. Vom Modem gehaltener Wakelock.
  1. Eine RIL-Anfrage wird gesendet und das Modem erhält einen Wakelock, um diese Anfrage zu verarbeiten.
  2. Das Modem sendet eine Bestätigung, die die Java-Seite veranlasst, den Wakelock-Zähler zu dekrementieren und ihn freizugeben, wenn der Zählerwert 0 ist.

    Hinweis: Die Wakelock-Timeout-Dauer für die Anforderungs-Bestätigungs-Sequenz wäre kleiner als die aktuell verwendete Timeout-Dauer, da die Bestätigung relativ schnell empfangen werden sollte.

  3. Nach der Verarbeitung der Anfrage sendet das Modem einen Interrupt an den Herstellercode, der Wakelock anfordert und eine Antwort an ril.cpp sendet, das wiederum Wakelock anfordert und eine Antwort an die Java-Seite sendet.
  4. Wenn die Antwort die Java-Seite erreicht, wird ein Wakelock erworben und eine Antwort an den Aufrufer zurückgegeben.
  5. Nachdem die Antwort von allen Modulen verarbeitet wurde, wird die Bestätigung (über den Socket) zurück an ril.cpp gesendet, das dann den in Schritt 3 erworbenen Wakelock freigibt.

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

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

Szenario: Unaufgeforderte RIL-Antwort

In diesem Szenario verfügen unaufgeforderte RIL-Antworten über ein Wakelock-Typ-Flag, das angibt, ob für die Anbieterantwort ein Wakelock erworben werden muss. Wenn das Flag gesetzt ist, wird ein zeitgesteuerter Wakelock gesetzt und die Antwort wird über einen Socket an die Java-Seite gesendet. Wenn der Timer abläuft, wird der Wakelock freigegeben. Der zeitgesteuerte Wakelock könnte für verschiedene unaufgeforderte RIL-Antworten zu lang oder zu kurz sein.

Abbildung 4. Unaufgeforderte RIL-Antwort.

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

Abbildung 5. Verwendung von Bestätigung anstelle von zeitgesteuertem Wakelock.

Validierung neu gestalteter Wakelocks

Stellen Sie sicher, dass RIL-Aufrufe als synchron oder asynchron identifiziert werden. Da der Batteriestromverbrauch von der Hardware/Plattform abhängig sein kann, sollten Anbieter einige interne Tests durchführen, um herauszufinden, ob die Verwendung der neuen Wakelock-Semantik für asynchrone Aufrufe zu Einsparungen bei der Batterieleistung führt.