RIL リファクタリング

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

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

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

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

拡張 RIL エラーコードの実装

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

Android 7.x 以降では、現在 GENERIC_FAILURE に分類されているエラーについて、OEM は各エラーに関連付けられた別々のエラーコード値を返すことができます。カスタム エラーコードを公開したくない OEM は、OEM_ERROR_1OEM_ERROR_X としてマッピングされた別個の整数セット(1〜x など)でエラーを返すことができます。ベンダーは、このようにマスクされて返される各エラーコードが、コード内の一意のエラー理由にマッピングされていることを確認する必要があります。OEM から一般的なエラーが返されるたびに GENERIC_FAILURE エラーコードの正確な原因を特定するのに時間がかかったり、特定できなかったりしましたが、具体的なエラーコードを使用すれば 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 呼び出しが同期または非同期として識別されることを確認します。電池消費量はハードウェアとプラットフォームに左右されるため、ベンダーは内部テストを行って、非同期呼び出しに新しいウェイクロック セマンティクスを使用した場合に、電池の消費を節約できるかどうかを確認する必要があります。