W Androidzie 7.0 interfejs RIL (Radio Interface Layer) został przebudowany za pomocą zestawu funkcji, które poprawiają jego działanie. Aby wdrożyć te funkcje, partner musi wprowadzić zmiany w kodze. Są one opcjonalne, ale zalecane. Zmiany w refaktoryzacji są zgodne z wsteczną, więc wcześniejsze implementacje przekształconych funkcji nadal działają.
Refaktoryzacja RIL obejmuje te ulepszenia:
- Kody błędów RIL Umożliwia stosowanie określonych kodów błędów oprócz dotychczasowego kodu
GENERIC_FAILURE
. Pomaga to w rozwiązywaniu problemów, ponieważ zawiera bardziej szczegółowe informacje o ich przyczynach. - Wersje RIL. Zawiera dokładniejsze informacje o wersji i łatwiej je skonfigurujesz.
- Komunikacja RIL za pomocą blokad budzenia. poprawić wydajność baterii urządzenia.
Możesz wdrożyć dowolne z wymienionych wyżej ulepszeń lub wszystkie. Więcej informacji znajdziesz w komentarzach do kodu dotyczących wersji RIL w https://android.googlesource.com/platform/hardware/ril/+/main/include/telephony/ril.h
.
Wdrożenie rozszerzonych kodów błędów RIL
Prawie wszystkie wywołania RIL mogą zwracać kod błędu GENERIC_FAILURE
w odpowiedzi na błąd. Jest to problem ze wszystkimi odpowiedziami zwracanymi przez OEM-ów, co może utrudniać debugowanie problemu na podstawie raportu o błędzie, jeśli wywołania RIL zwracają ten sam kod błędu GENERIC_FAILURE
z różnych powodów. Dostawcy mogą potrzebować sporo czasu, aby zidentyfikować, która część kodu mogła zwrócić kod GENERIC_FAILURE
.
W Androidzie 7.x i nowszych OEM może zwracać oddzielną wartość kodu błędu związaną z każdym błędem, który jest obecnie sklasyfikowany jako GENERIC_FAILURE
. Producenci OEM, którzy nie chcą ujawniać swoich niestandardowych kodów błędów, mogą zwracać błędy jako odrębny zbiór liczb całkowitych (np. od 1 do x), mapowanych jako OEM_ERROR_1
na OEM_ERROR_X
. Dostawcy powinni zadbać o to, aby każdy taki zamaskowany kod błędu był powiązany z unikalnym powodem błędu w kodzie. Korzystanie z określonych kodów błędów może przyspieszyć debugowanie RIL, gdy OEM zwraca ogólne błędy, ponieważ ustalenie dokładnej przyczyny kodu błędu GENERIC_FAILURE
może zająć zbyt dużo czasu (a czasami jest niemożliwe).
Dodatkowo ril.h
dodaje więcej kodów błędów dla typów enumeracji RIL_LastCallFailCause
i RIL_DataCallFailCause
, dzięki czemu kod dostawcy może uniknąć zwracania ogólnych błędów, takich jak CALL_FAIL_ERROR_UNSPECIFIED
i PDP_FAIL_ERROR_UNSPECIFIED
.
Weryfikowanie kodów błędów RIL w rozszerzonej wersji
Po dodaniu nowych kodów błędów zamiast kodu GENERIC_FAILURE
sprawdź, czy nowe kody błędów są zwracane przez wywołanie RIL zamiast kodu GENERIC_FAILURE
.
Wdrażanie rozszerzonej wersji RIL
Wersje RIL w starszych wersjach Androida były problematyczne: sama wersja była niedokładna, mechanizm raportowania wersji RIL był niejasny (co powodowało, że niektórzy dostawcy raportowali nieprawidłową wersję), a obejście w celu oszacowania wersji było podatne na niedokładności.
W Androidzie 7.x i nowszych funkcja ril.h
dokumentuje wszystkie wartości wersji RIL, opisuje odpowiednią wersję RIL i wypisuje wszystkie zmiany w tej wersji. Wprowadzając zmiany odpowiadające wersji RIL, sprzedawcy muszą zaktualizować wersję w kodzie i zwrócić tę wersję w pliku RIL_REGISTER
.
Weryfikowanie wersji rozszerzonego interfejsu RIL
Sprawdź, czy podczas wywołania RIL_REGISTER
zwracana jest wersja RIL odpowiadająca Twojemu kodowi RIL (a nie RIL_VERSION
zdefiniowany w ril.h
).
Implementacja komunikacji RIL za pomocą blokad aktywacji
Blokady czasowej aktywacji są używane w komunikacji RIL w nieprecyzyjny sposób, co negatywnie wpływa na wydajność baterii. W Androidzie 7.x i nowszych możesz zwiększyć wydajność, klasyfikując żądania RIL i aktualizując kod, aby obsługiwał blokady budzenia w różny sposób w zależności od typu żądania.
Klasyfikowanie żądań dotyczących interakcji z reklamą
Prośby o uzyskanie informacji o wycenie reklamy mogą być prośbami zainicjowanymi przez użytkownika lub nie. Dostawcy powinni dodatkowo klasyfikować żądane prośby w jeden z tych sposobów:
- synchronicznie. prośby, na które odpowiedź nie wymaga dużo czasu. Na przykład:
RIL_REQUEST_GET_SIM_STATUS
. - asynchronicznie. prośby, na które odpowiedź zajmuje dużo czasu. Na przykład:
RIL_REQUEST_QUERY_AVAILABLE_NETWORKS
.
Żądane żądania RIL wysyłane asynchronicznie mogą zająć sporo czasu. Po otrzymaniu potwierdzenia z kodu dostawcy RIL Java zwalnia blokadę aktywacji, co może spowodować przejście procesora aplikacji z stanu bezczynności do stanu zawieszenia. Gdy odpowiedź jest dostępna z kodu dostawcy, RIL Java (procesor aplikacji) ponownie uzyskuje blokadę aktywacji, przetwarza odpowiedź, a potem wraca do stanu bezczynności. Takie przechodzenie z stanu bezczynności do zawieszenia i z powrotem do bezczynności może zużywać dużo energii.
Jeśli czas reakcji nie jest wystarczająco długi, utrzymywanie WakeLocka i pozostawianie urządzenia w stanie bezczynności przez cały czas oczekiwania na odpowiedź może być bardziej energooszczędne niż przejście w stan zawieszenia przez zwolnienie WakeLocka i przebudzenie, gdy odpowiedź dotrze do urządzenia. Do określenia wartości progowej czasu T, w którym moc zużywana przez pozostawanie w stanie bezczynności przez cały czas T jest większa niż moc zużywana przez przejście z stanu bezczynności do zawieszenia i z powrotem do stanu bezczynności w tym samym czasie T, dostawcy powinni używać pomiarów zużycia energii specyficznych dla platformy. Gdy czas T jest znany, polecenia RIL, które zajmują więcej niż czas T, można zaklasyfikować jako asynchroniczne, a pozostałe jako synchroniczne.
Scenariusze komunikacji RIL
Diagramy poniżej przedstawiają typowe scenariusze komunikacji z RIL oraz podają rozwiązania dotyczące modyfikowania kodu w celu obsługi żądań RIL (z wyrażeniem zgody i bez niego).
Uwaga: szczegółowe informacje o implementacji funkcji użytych na poniższych diagramach znajdziesz w metodach acquireWakeLock()
, decrementWakeLock()
i clearWakeLock(
w ril.cpp
.
Scenariusz: żądanie RIL i wywołana odpowiedź asynchroniczna
W tym scenariuszu, jeśli oczekiwana odpowiedź RIL ma zająć dużo czasu (np. odpowiedź na RIL_REQUEST_GET_AVAILABLE_NETWORKS
), blokada aktywacji jest utrzymana przez długi czas po stronie procesora aplikacji. Długie oczekiwanie może być też spowodowane problemami z modemem.
Rozwiązanie 1: modem utrzymuje wakelocka dla żądania RIL i odpowiedzi asynchronicznej.
- Przesyłane jest żądanie RIL, a modem uzyskuje blokadę aktywacji w celu przetworzenia tego żądania.
- Modem wysyła potwierdzenie, które powoduje, że strona Java zmniejsza wartość licznika blokady aktywacji, a gdy jego wartość wynosi 0, to licznik jest zwalniany.
Uwaga: czas oczekiwania na zablokowanie zegara dla sekwencji żądanie–potwierdzenie będzie krótszy niż obecnie używany czas oczekiwania, ponieważ potwierdzenie powinno zostać odebrane dość szybko.
- Po przetworzeniu żądania modem wysyła przerwanie do kodu dostawcy, który uzyskuje blokadę aktywacji i wysyła odpowiedź do pliku ril.cpp, który z kolei uzyskuje blokadę aktywacji i wysyła odpowiedź do strony Javy.
- Gdy odpowiedź dotrze do strony Java, uzyskasz dostęp do wakelocka, a odpowiednia odpowiedź zostanie zwrócona do wywołującego.
- Po przetworzeniu odpowiedzi przez wszystkie moduły potwierdzenie jest wysyłane (przez gniazdo) z powrotem do
ril.cpp
, który następnie zwalnia blokadę wybudzania uzyskaną w kroku 3.
Rozwiązanie 2: modem nie blokuje wakelocka, a odpowiedź jest szybka (synchroniczna odpowiedź na żądanie RIL). Zachowanie synchroniczne lub asynchroniczne jest zakodowane na stałe w przypadku konkretnego polecenia RIL i określane w ramach poszczególnych wywołań.
- Prośba RIL jest wysyłana przez wywołanie funkcji
acquireWakeLock()
po stronie Java. - Kod dostawcy nie musi uzyskiwać blokady ekranu, może przetwarzać żądanie i szybko na nie odpowiadać.
- Gdy odpowiedź zostanie odebrana po stronie Java, wywoływana jest funkcja
decrementWakeLock()
, która zmniejsza licznik blokady aktywacji i zwalnia blokadę, jeśli wartość licznika wynosi 0.
Scenariusz: niechciana odpowiedź RIL
W tym scenariuszu nieproszone odpowiedzi RIL mają w swoim nagłówku flagę typu wakelock, która wskazuje, czy w przypadku odpowiedzi od dostawcy należy użyć wakelocka. Jeśli flaga jest ustawiona, zostaje ustawiony czasowy blokażu i odpowiedź jest wysyłana przez gniazdo do strony Java. Gdy kończy się czas działania minutnika, blokada jest odblokowywana. Czas trwania blokady ekranu może być za długi lub za krótki w przypadku różnych niechcianych odpowiedzi RIL.
Rozwiązanie: potwierdzenie jest wysyłane z kodu Java do strony natywnej (ril.cpp
), a nie przytrzymuje się blokady aktywacji na czas określony w czasie na stronie natywnej podczas wysyłania niechcianej odpowiedzi.
Weryfikowanie przeprojektowanych blokad aktywacji
Sprawdź, czy wywołania RIL są identyfikowane jako synchroniczne lub asynchroniczne. Ponieważ zużycie energii baterii może zależeć od sprzętu lub platformy, dostawcy powinni przeprowadzić wewnętrzne testy, aby sprawdzić, czy korzystanie z nowej semantyki wakelocka w przypadku wywołań asynchronicznych prowadzi do oszczędzania energii baterii.