發布日期:
Android 11 (API 級別 30) - Thermal API
Android 12 (API 級別 31) - NDK API
(預先發布版) Android 15 (DP1) - getThermalHeadroomThresholds()
應用程式可能的效能會受到裝置的熱力狀態限制,這類狀態可能會因天氣、近期使用情況和裝置的熱力設計等特性而異。裝置只能暫時維持一定時段的高效能,之後就會為了防止過熱而進行節流。實作作業的一大目標,是要在不超出熱溫限制的情況下達成效能目標。Thermal API 無需特定裝置最佳化即可實現。此外,在針對效能問題進行偵錯時,知道裝置的熱力狀態是否會限制效能非常重要。此外,在針對效能問題進行偵錯時,知道裝置的熱力狀態是否會限制效能非常重要。
遊戲引擎通常會提供執行階段效能參數,可調整引擎加諸於裝置的工作負載。舉例來說,這些參數可以設定工作站執行緒數量、大型與小型核心的工作站執行緒相依性、GPU 擬真度選項,以及 framebuffer 解析度。在 Unity Engine 中,遊戲開發人員可以使用 Adaptive Performance 外掛程式變更品質設定,藉此調整工作負載。如果使用 Unreal Engine,請使用「擴充性設定」動態調整品質等級。
當裝置接近不安全的熱力狀態時,遊戲可以透過這些參數來減少工作負載,藉此避免發生過熱保護情形。如要避免發生過熱保護情形,您應監控裝置的熱力狀態,並主動調整遊戲引擎工作負載。裝置一旦過熱,工作負載就必須降低至永續效能等級以下才能散熱。當熱力上升空間降低到安全等級後,遊戲可以再次提升品質設定,但請務必找出能持續改善的品質等級,以便獲得最佳遊玩時間。
您可以藉由輪詢 getThermalHeadroom
方法來監控裝置的熱力狀態。這個方法可預測裝置在不過熱的情況下,可維持目前效能等級的時間長度。如果這段時間比執行工作負載所需時間還短,則遊戲應將工作負載降低至永續等級。舉例來說,遊戲可以改用小型核心、降低影格速率或擬真度。
獲取熱管理經理
若要使用 Thermal Manager,您需要先取得 Thermal Manager。
C++
AThermalManager* thermal_manager = AThermal_acquireManager();
Java
PowerManager powerManager = (PowerManager)this.getSystemService(Context.POWER_SERVICE);
預測熱力上升空間 x 秒,進一步控制
您可以要求系統根據目前的工作負載預測未來溫度 (x 秒)。如此一來,您就能減少工作負載來防止發生過熱保護的情況,進而獲得更精細的控管和更多回應時間。
結果範圍從 0.0f (無節流,THERMAL_STATUS_NONE
) 到 1.0f (密集節流,THERMAL_STATUS_SEVERE
)。如果遊戲中有不同的影像品質等級,請遵循我們的《熱力上升指南》。
C++
float thermal_headroom = AThermal_getThermalHeadroom(10);
ALOGI("ThermalHeadroom in 10 sec: %f", thermal_headroom);
Java
float thermalHeadroom = powerManager.getThermalHeadroom(10);
Log.d("ADPF", "ThermalHeadroom in 10 sec: " + thermalHeadroom);
或者,依熱能狀態尋求說明
每種裝置型號的設計方式都不盡相同。部分裝置或許可以更有效地分配熱,因此在進行節流前,可能能夠承受較高熱力上升空間。如要讀取已簡化的熱力上升範圍範圍,可以檢查熱力狀態,藉此瞭解目前裝置上的熱力上升空間值。
C++
AThermalStatus thermal_status = AThermal_getCurrentThermalStatus(thermal_manager);
ALOGI("ThermalStatus is: %d", thermal_status);
Java
int thermalStatus = powerManager.getCurrentThermalStatus();
Log.d("ADPF", "ThermalStatus is: " + thermalStatus);
在熱力狀態變更時收到通知
您也可以避免輪詢 thermalHeadroom
,直到 thermalStatus
達到特定等級 (例如:THERMAL_STATUS_LIGHT
)。如要這麼做,您可以註冊回呼,讓系統在狀態變更時通知您。
C++
int result = AThermal_registerThermalStatusListener(thermal_manager, callback);
if ( result != 0 ) {
// failed, check whether you have previously registered callback that
// hasn’t been unregistered
}
Java
// PowerManager.OnThermalStatusChangedListener is an interface, thus you can
// also define a class that implements the methods
PowerManager.OnThermalStatusChangedListener listener = new
PowerManager.OnThermalStatusChangedListener() {
@Override
public void onThermalStatusChanged(int status) {
Log.d("ADPF", "ThermalStatus changed: " + status);
// check the status and flip the flag to start/stop pooling when
// applicable
}
};
powerManager.addThermalStatusListener(listener);
完成後請記得移除事件監聽器
C++
int result = AThermal_unregisterThermalStatusListener(thermal_manager, callback);
if ( result != 0 ) {
// failed, check whether the callback has been registered previously
}
Java
powerManager.removeThermalStatusListener(listener);
清除
完成操作後,請清理您取得的 thermal_manager。如果您是使用 Java,系統可自動為您收集 PowerManager 參照的資料。但如果您是透過 JNI 使用 Java API,且已有參照,請記得清除參照!
C++
AThermal_releaseManager(thermal_manager);
如需透過 C++ API (NDK API) 和 Java API (透過 JNI) 在原生 C++ 遊戲中實作 Thermal API 的完整指南,請參閱「適應性程式碼研究室」一節中的「整合 Thermal API」一節。
熱力上升空間規範
您可以藉由輪詢 getThermalHeadroom
方法來監控裝置的熱力狀態。這個方法會預測裝置在達到 THERMAL_STATUS_SEVERE
前可維持目前效能等級的時間長度。舉例來說,如果 getThermalHeadroom(30)
傳回 0.8,表示進步空間預計將在 30 秒後達到 0.8,且與嚴重節流相距 0.2 距離 (1.0)。如果這段時間比執行工作負載所需時間還短,則遊戲應將工作負載降低至永續等級。舉例來說,遊戲可以降低畫面更新率、降低擬真度,或減少網路連線工作。
熱力狀態與意義
- 如果裝置未處於過熱保護狀態:
- 已有節流情形,但對效能沒有重大影響:
- 發生會影響效能的大幅度過熱保護情形:
Thermal API 的裝置限制
由於在舊型裝置上實作熱力 API,因此 Thermal API 有一些已知的限製或額外規定。這些限制及使用方式如下:
- 請勿太常呼叫
GetThermalHeadroom()
API。這麼做會導致 API 傳回 NaN。每秒最多只能呼叫一次。 - 如果
GetThermalHeadroom()
的初始值為 NaN,表示裝置上無法使用該 API - 如果
GetThermalHeadroom()
傳回較高值 (例如 0.85 以上),且GetCurrentThermalStatus()
仍然傳回THERMAL_STATUS_NONE
,表示狀態可能未更新。請使用經驗法則來估算正確的溫度節流狀態,或是在沒有getCurrentThermalStatus()
的情況下使用getThermalHeadroom()
。
經驗法則範例:
- 檢查是否支援 Thermal API。
isAPISupported()
會檢查第一個呼叫getThermalHeadroom
的值,確認該值不是 0 或 NaN,並在第一個值是 0 或 NaN 的情況下略過 API。 - 如果
getCurrentThermalStatus()
傳回THERMAL_STATUS_NONE
以外的值,表示裝置已受到過熱保護。 - 如果
getCurrentThermalStatus()
持續傳回THERMAL_STATUS_NONE
,不一定代表裝置未處於過熱保護狀態。這代表裝置不支援getCurrentThermalStatus()
。請檢查getThermalHeadroom()
的傳回值,確認裝置條件。 - 如果
getThermalHeadroom()
傳回 > 1.0 的值,則狀態實際上可能為THERMAL_STATUS_SEVERE
以上,請立即減少工作負載,並維持較低的工作負載,直到getThermalHeadroom()
傳回較低的值為止 - 如果
getThermalHeadroom()
傳回 0.95 的值,則狀態實際上可能是THERMAL_STATUS_MODERATE
以上,請立即減少工作負載,並保留注意事項,避免高讀數。 - 如果
getThermalHeadroom()
傳回 0.85 的值,則狀態實際上可能是THERMAL_STATUS_LIGHT
,請保持注意並盡可能減少工作負載
虛擬程式碼:
bool isAPISupported() {
float first_value_of_thermal_headroom = getThermalHeadroom();
if ( first_value_of_thermal_headroom == 0 ||
first_value_of_thermal_headroom == NaN ) {
// Checked the thermal Headroom API's initial return value
// it is NaN or 0,so, return false (not supported)
return false;
}
return true;
}
if (!isAPISupported()) {
// Checked the thermal Headroom API's initial return value, it is NaN or 0
// Don’t use the API
} else {
// Use thermalStatus API to check if it returns valid values.
if (getCurrentThermalStatus() > THERMAL_STATUS_NONE) {
// The device IS being thermally throttled
} else {
// The device is not being thermally throttled currently. However, it
// could also be an indicator that the ThermalStatus API may not be
// supported in the device.
// Currently this API uses predefined threshold values for thermal status
// mapping. In the future you may be able to query this directly.
float thermal_headroom = getThermalHeadroom();
if ( thermal_headroom > 1.0) {
// The device COULD be severely throttled.
} else if ( thermal_headroom > 0.95) {
// The device COULD be moderately throttled.
} else if ( thermal_headroom > 0.85) {
// The device COULD be experiencing light throttling.
}
}
}
圖表: