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 及更高版本中,OEM 可以返回與當前歸類為GENERIC_FAILURE的每個不同錯誤相關聯的不同錯誤代碼值。不想公開顯示其自定義錯誤代碼的 OEM 可以將錯誤返回為一組不同的整數(例如 1 到 x),映射為OEM_ERROR_1OEM_ERROR_X 。供應商應確保返回的每個此類屏蔽錯誤代碼都映射到代碼中的唯一錯誤原因。每當 OEM 返回一般錯誤時,使用特定錯誤代碼可以加速 RIL 調試,因為通常需要花費太多時間來確定GENERIC_FAILURE錯誤代碼的確切原因(有時無法弄清楚)。

此外, 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_VERSION中定義的ril.h )。

使用喚醒鎖實現 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.cpp 中的ril.cpp acquireWakeLock()decrementWakeLock()clearWakeLock( ) 方法。

場景:RIL 請求和請求的異步響應

在這種情況下,如果預計 RIL 請求響應需要相當長的時間(即對RIL_REQUEST_GET_AVAILABLE_NETWORKS的響應),則喚醒鎖會在應用程序處理器端保持很長時間。調製解調器問題也可能導致長時間等待。

圖 1. RIL 請求的異步響應。

解決方案 1:調製解調器為 RIL 請求和異步響應持有喚醒鎖。

圖 2.調製解調器持有的喚醒鎖。
  1. 發送 RIL 請求,調製解調器獲取喚醒鎖以處理該請求。
  2. 調製解調器發送確認,導致 Java 端遞減喚醒鎖計數器,並在計數器值為 0 時釋放它。

    注意:請求-確認序列的喚醒鎖超時持續時間將小於當前使用的超時持續時間,因為應該很快收到確認。

  3. 處理完請求後,modem 向獲取wakelock 的供應商代碼發送中斷並向ril.cpp 發送響應,ril.cpp 反過來又獲取wakelock 並向Java 端發送響應。
  4. 當響應到達 Java 端時,獲取喚醒鎖並向調用者返迴響應。
  5. 在所有模塊處理完響應後,會(通過套接字)將確認發送回ril.cpp ,然後釋放在步驟 3 中獲取的喚醒鎖。

方案二: modem不持有wakelock,響應快(同步RIL請求和響應)。同步與異步行為是針對特定 RIL 命令進行硬編碼的,並根據逐個調用來決定。

圖 3.調製解調器未持有喚醒鎖。
  1. 通過在 Java 端調用acquireWakeLock()發送 RIL 請求。
  2. 供應商代碼無需獲取喚醒鎖,可以快速處理請求和響應。
  3. 當 Java 端收到響應時,會調用decrementWakeLock() ,它會減少喚醒鎖計數器,如果計數器值為 0,則釋放喚醒鎖。

場景:RIL 主動響應

在這種情況下,RIL 主動響應中有一個喚醒鎖類型標誌,指示是否需要為供應商響應獲取喚醒鎖。如果設置了標誌,則會設置定時喚醒鎖,並通過套接字將響應發送到 Java 端。當定時器到期時,喚醒鎖被釋放。對於不同的 RIL 主動響應,定時喚醒鎖可能太長或太短。

圖 4. RIL 主動響應。

解決方案:從 Java 代碼向本機端 ( ril.cpp ) 發送確認,而不是在發送主動響應時在本機端保持定時喚醒鎖。

圖 5.使用 ack 代替定時喚醒鎖。

驗證重新設計的喚醒鎖

驗證 RIL 調用被標識為同步或異步。由於電池功耗可能取決於硬件/平台,因此供應商應該進行一些內部測試,以確定使用新的異步調用喚醒鎖語義是否可以節省電池電量。