熱 API

發布日期

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 方法來監控裝置的熱力狀態。這個方法可預測裝置在不過熱的情況下,可維持目前效能等級的時間長度。如果這段時間比執行工作負載所需時間還短,則遊戲應將工作負載降低至永續等級。舉例來說,遊戲可以改用小型核心、降低影格速率或擬真度。

ADPF Thermal API 預先整合
圖 1.未主動監控 getThermalHeadroom 的熱力上升空間
ADPF Thermal API 後整合
圖 2. 主動監控「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()

經驗法則範例:

  1. 檢查是否支援 Thermal API。isAPISupported() 會檢查第一個呼叫 getThermalHeadroom 的值,確認該值不是 0 或 NaN,並在第一個值是 0 或 NaN 的情況下略過 API。
  2. 如果 getCurrentThermalStatus() 傳回 THERMAL_STATUS_NONE 以外的值,表示裝置已受到過熱保護。
  3. 如果 getCurrentThermalStatus() 持續傳回 THERMAL_STATUS_NONE,不一定代表裝置未處於過熱保護狀態。這代表裝置不支援 getCurrentThermalStatus()。請檢查 getThermalHeadroom() 的傳回值,確認裝置條件。
  4. 如果 getThermalHeadroom() 傳回 > 1.0 的值,則狀態實際上可能為 THERMAL_STATUS_SEVERE 以上,請立即減少工作負載,並維持較低的工作負載,直到 getThermalHeadroom() 傳回較低的值為止
  5. 如果 getThermalHeadroom() 傳回 0.95 的值,則狀態實際上可能是 THERMAL_STATUS_MODERATE 以上,請立即減少工作負載,並保留注意事項,避免高讀數。
  6. 如果 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.
      }
    }
  }

圖表:

ADPF 經驗法則範例
圖 3.「啟發式 API」的範例,用於判斷在舊裝置上支援的 Thermal API 支援功能