熱能 API

已發布

Android 11 (API 級別 30) - Thermal API

Android 12 (API 級別 31) - NDK API

(預先發布版) Android 15 (DP1) - getThermalHeadroomThresholds()

應用程式的潛在效能會受限於裝置的熱力狀態,這可能會因天氣、最近使用情況和裝置的熱力設計等特性而異。裝置只能暫時維持一定時段的高效能,之後就會為了防止過熱而進行節流。實作作業的一大目標,是要在不超出熱溫限制的情況下達成效能目標。溫度 API 可讓您不必進行裝置專屬最佳化。此外,在針對效能問題進行偵錯時,知道裝置熱力狀態是否限制效能十分重要。

遊戲引擎通常會提供執行階段效能參數,可調整引擎加諸於裝置的工作負載。舉例來說,這些參數可以設定工作站執行緒數量、大型與小型核心的工作站執行緒相依性、GPU 擬真度選項,以及 framebuffer 解析度。在 Unity Engine 中,遊戲開發人員可以使用Adaptive Performance 外掛程式變更品質設定,藉此調整工作負載。針對 Unreal Engine,請使用可調整性設定動態調整品質等級。

當裝置接近不安全的熱力狀態時,遊戲可以透過這些參數來減少工作負載,藉此避免發生過熱保護情形。如要避免發生過熱保護情形,您應監控裝置的熱力狀態,並主動調整遊戲引擎工作負載。裝置一旦過熱,工作負載就必須降低至永續效能等級以下才能散熱。熱能裕度降至較安全的程度後,遊戲可以再次提高品質設定,但請務必找到可持續的品質等級,以便獲得最佳遊戲時間。

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

ADPF Thermal API 預先整合
圖 1. 未主動監控 getThermalHeadroom 的熱力上升空間
ADPF Thermal API 整合後
圖 2. 熱力上升空間,並主動監控 `getThermalHeadroom`

取得 Thermal Manager

如要使用 Thermal API,您必須先取得 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);

在熱力狀態變更時收到通知

您也可以在 thermalStatus 達到特定層級 (例如:THERMAL_STATUS_LIGHT) 之前,避免輪詢 thermalHeadroom。如要這麼做,您可以註冊回呼,讓系統在狀態變更時通知您。

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++ 遊戲中使用 C++ API (NDK API) 和 Java API (透過 JNI) 實作 Thermal API,請參閱「適應性程式碼研究室」一節中的「整合 Thermal API」一節。

熱力上升空間規範

您可以藉由輪詢 getThermalHeadroom 方法來監控裝置的熱力狀態。這個方法可預測裝置在達到 THERMAL_STATUS_SEVERE 之前,可維持目前效能等級的時間長度。舉例來說,如果 getThermalHeadroom(30) 傳回 0.8,表示在 30 秒內,預定可用空間會達到 0.8,距離嚴重限速 (1.0) 的距離為 0.2。如果這段時間比執行工作負載所需時間還短,則遊戲應將工作負載降低至永續等級。舉例來說,遊戲可以降低影格速率、降低擬真度或減少網路連線工作。

溫度狀態和含義

Thermal API 的裝置限制

由於在舊版裝置上實作 Thermal API,因此 Thermal API 有一些已知的限制或額外需求。限制和解決方法如下:

  • 請勿過度頻繁呼叫 GetThermalHeadroom() API。如此一來,API 就會傳回 NaN。每 10 秒不得呼叫多次。
  • 請避免從多個執行緒呼叫,因為這會使確保呼叫頻率變得更加困難,並可能導致 API 傳回 NaN
  • 如果 GetThermalHeadroom() 的初始值為 NaN,則裝置無法使用 API
  • 如果 GetThermalHeadroom() 傳回高值 (例如 0.85 以上),而 GetCurrentThermalStatus() 仍傳回 THERMAL_STATUS_NONE,則狀態可能未更新。使用推論法估算正確的溫度調節狀態,或只使用 getThermalHeadroom() 而不使用 getCurrentThermalStatus()

經驗法則示例:

  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.使用熱點檢測法判斷舊裝置支援的 Thermal API 範例