RIL リファクタリング

Android 7.0 では、一連の機能を使用して無線インターフェース レイヤ(RIL)をリファクタリングし、RIL 機能を改善しました。これらの機能は必須ではありませんが推奨されており、実装するにはパートナー コードを変更する必要があります。リファクタリングによる変更は下位互換性があるため、リファクタリングされた機能の以前の実装は引き続き機能します。

RIL リファクタリングでは次の改善が行われました。

  • RIL エラーコード。既存の GENERIC_FAILURE コードに加えて、具体的なエラーコードが使用可能になりました。エラーの原因に関する詳しい情報が提供されるため、トラブルシューティングに役立ちます。
  • RIL のバージョニング。バージョン情報をより正確かつ簡単に構成できるようになりました。
  • ウェイクロックを使用した RIL 通信。デバイスの電池性能が改善されました。

これらの改善の一部またはすべてを実装できます。詳しくは、https://android.googlesource.com/platform/hardware/ril/+/main/include/telephony/ril.h の RIL のバージョニングに関するコードコメントをご覧ください。

拡張 RIL エラーコードを実装する

ほぼすべての RIL リクエスト呼び出しで、エラーの場合に返されるのは GENERIC_FAILURE エラーコードです。これは、OEM から返されるすべての応答に関係する問題であり、RIL 呼び出しで異なる理由に対して同じ GENERIC_FAILURE エラーコードが返された場合、バグレポートから問題をデバッグするのが困難になる可能性があります。したがってベンダーは、コードのどの部分で GENERIC_FAILURE コードが返されたのかを特定するだけでもかなりの時間を要する場合があります。

Android 7.x 以降では、現在 GENERIC_FAILURE に分類されている複数のエラーについて、OEM が実際のエラーに関連付けられた個別のエラーコード値を返すことができるようになりました。カスタム エラーコードの公開を希望しない OEM は、OEM_ERROR_1 として OEM_ERROR_X にマッピングされた独自の整数のセット(1〜x など)をエラーとして返すことができます。ベンダーは、このようにマスクされて返される各エラーコードが、コード内の一意のエラー理由にマッピングされていることを確認する必要があります。GENERIC_FAILURE エラーコードの正確な原因の特定には非常に長い時間を要することが頻繁にあり、特定できない場合もありますが、OEM から一般的なエラーが返されるたびに具体的なエラーコードを使用すれば、RIL のデバッグに要する時間を短縮できます。

さらに、ril.h で列挙型の RIL_LastCallFailCauseRIL_DataCallFailCause のエラーコードが追加されたため、ベンダーコードによって CALL_FAIL_ERROR_UNSPECIFIEDPDP_FAIL_ERROR_UNSPECIFIED などの一般的なエラーが返されることを回避できます。

拡張 RIL エラーコードを検証する

新しいエラーコードを追加して GENERIC_FAILURE コードを置き換えたら、RIL 呼び出しによって GENERIC_FAILURE ではなく新しいエラーコードが返されることを確認します。

拡張 RIL バージョニングを実装する

以前の Android リリースでの RIL バージョニングには、バージョン自体が不正確である、RIL バージョンを報告するメカニズムが不明確である(そのためベンダーが間違ったバージョンを報告する場合がある)、バージョンの推定方法を誤りやすいなどの問題がありました。

Android 7.x 以降では、ril.h ですべての RIL バージョン値がドキュメント化され、対応する RIL バージョンについての説明がなされており、そのバージョンのすべての変更がリストされています。RIL バージョンに対応する変更を行う場合、ベンダーはコード内でバージョンを更新し、RIL_REGISTER でそのバージョンを返す必要があります。

拡張 RIL バージョニングを検証する

RIL_REGISTER で RIL コードに対応する RIL バージョン(ril.h に定義されている RIL_VERSION ではない)が返されることを確認します。

ウェイクロックを使用した RIL 通信を実装する

RIL 通信では時間指定されたウェイクロックが正しく使用されず、バッテリー性能に悪影響があります。Android 7.x 以降では、RIL リクエストを分類し、リクエストの種類ごとに異なる方法でウェイクロックを処理するようにコードを更新することで、パフォーマンスを改善できます。

RIL リクエストを分類する

RIL リクエストは、要請型または非要請型のいずれかに分類できます。ベンダーは、要請型リクエストをさらに次のいずれかに分類する必要があります。

  • 同期型。応答に長時間を要しないリクエスト(例: RIL_REQUEST_GET_SIM_STATUS)。
  • 非同期型。応答に長時間を要するリクエスト(例: RIL_REQUEST_QUERY_AVAILABLE_NETWORKS)。

非同期型の承諾済み RIL リクエストは長時間を要します。ベンダーコードから肯定応答を受信した後、RIL Java はウェイクロックを解放します。これにより、アプリ プロセッサがアイドル状態から停止状態になる可能性があります。ベンダーコードからのレスポンスが得られると、RIL Java(アプリ プロセッサ)はウェイクロックを再取得し、レスポンスを処理してからアイドル状態に戻ります。このようにアイドル状態から停止状態を経てアイドル状態に遷移する場合は、多くの電力を消費する可能性があります。

応答時間が長すぎない場合、ウェイクロックを解放して停止状態になり、レスポンスが届いたときにスリープ状態から復帰するよりも、ウェイクロックを保持して応答の間アイドル状態を維持するほうが消費電力を抑えられます。ベンダーはプラットフォーム固有の電力測定値を使用して、時間 T のしきい値(時間 T の間にアイドル状態から停止状態に移行して再びアイドル状態に戻る場合よりも、同じ時間 T の間アイドル状態を維持した場合に消費電力が多くなる)を決定する必要があります。時間 T が判明したら、T よりも長い時間がかかる RIL コマンドは非同期に分類し、残りのコマンドは同期に分類できます。

RIL 通信のシナリオ

次の図で RIL 通信の一般的なシナリオを示し、RIL の要請型リクエストと非要請型リクエストを処理するコードの変更方法を紹介します。

注: 次の図で使用される関数の実装について詳しくは、ril.cppacquireWakeLock()decrementWakeLock()clearWakeLock( の各メソッドをご覧ください。

シナリオ: RIL リクエストと要請型非同期レスポンス

このシナリオでは、RIL の要請型レスポンスにかなりの時間がかかることが予想される場合(RIL_REQUEST_GET_AVAILABLE_NETWORKS に対するレスポンスなど)、アプリ プロセッサ側でウェイクロックが長時間保持されます。モデムの問題によって、長い待ち時間が発生することもあります。

図 1. RIL の要請型非同期レスポンス。

解決策 1: RIL リクエストと非同期型レスポンスの間、モデムがウェイクロックを保持します。

図 2. モデムによって保持されるウェイクロック。
  1. RIL リクエストが送信され、モデムはそのリクエストを処理するためにウェイクロックを取得します。
  2. モデムが肯定応答を送信すると Java サイドでウェイクロック カウンタが減り、カウンタ値が 0 になったときに解放されます。

    注: 肯定応答の受信にはあまり時間がかからないため、リクエスト / 肯定応答シーケンスのウェイクロック タイムアウト時間は、現在使用されているタイムアウト時間よりも短くなります。

  3. リクエストを処理した後、モデムがベンダーコードに割り込みを送信し、ベンダーコードがウェイクロックを取得して ril.cpp にレスポンスを送信します。次に ril.cpp がウェイクロックを取得して Java サイドにレスポンスを送信します。
  4. レスポンスが Java サイドに達すると、ウェイクロックが取得されて呼び出し元にレスポンスが返されます。
  5. レスポンスがすべてのモジュールで処理された後、肯定応答がソケットを介して ril.cpp に送り返されると、ステップ 3 で取得したウェイクロックが解放されます。

解決策 2: モデムはウェイクロックを保持せず、迅速にレスポンスが送信されます(同期 RIL リクエストとレスポンス)。同期または非同期の動作は、特定の RIL コマンド向けにハードコーディングされており、呼び出しごとに決まります。

図 3. モデムによって保持されないウェイクロック。
  1. RIL リクエストの送信は、Java サイドでの acquireWakeLock() の呼び出しによって行われます。
  2. ベンダーコードはウェイクロックを取得する必要がないため、迅速にリクエストを処理して応答できます。
  3. Java サイドでレスポンスが受信されると、decrementWakeLock() が呼び出されてウェイクロック カウンタが減り、カウンタ値が 0 になったときにウェイクロックが解放されます。

シナリオ: RIL の非要請型レスポンス

このシナリオでは、RIL の非要請型レスポンスにウェイクロック タイプのフラグが含まれ、ベンダー レスポンスのためにウェイクロックを取得する必要があるかどうかが示されます。フラグが設定されている場合、時間指定付きのウェイクロックが設定され、レスポンスがソケットを介して Java サイドに送信されます。タイマーが切れると、ウェイクロックが解放されます。時間指定付きのウェイクロックは、RIL の非要請型レスポンスによっては長すぎる、または短すぎる場合があります。

図 4. RIL の非要請型レスポンス。

解決策: 非要請型レスポンスの送信時にネイティブ サイド(ril.cpp)で時間指定付きのウェイクロックを保持するのではなく、Java コードからネイティブ サイドに肯定応答を送信します。

図 5. 時間指定付きのウェイクロックではなく肯定応答を使用する。

新しくなったウェイクロックを検証する

RIL 呼び出しが同期型または非同期型として識別されることを確認します。電池消費量はハードウェアとプラットフォームに左右されるため、ベンダーは内部テストを行って、非同期呼び出しに新しいウェイクロック セマンティクスを使用した場合に、電池の消費を節約できるかどうかを確認する必要があります。