Thermal API

发布日期

Android 11(API 级别 30)- Thermal API

Android 12(API 级别 31)- NDK API

(预览版)Android 15 (DP1) - getThermalHeadroomThresholds()

应用的潜在性能受设备热状态的限制,热状态可能会因天气、近期使用情况以及设备热设计等特性而异。设备只能在限定的时间内保持高性能水平,然后才会受到热限制。实现的关键目标是在不超出热限制的情况下实现性能目标。Thermal API 使您无需进行设备专属优化即可实现目标。此外,在调试性能问题时,了解设备的热状态是否限制了性能也非常重要。此外,在调试性能问题时,了解设备的热状态是否限制了性能也非常重要。

游戏引擎通常具有运行时性能参数,可以调整引擎对设备施加的工作负载。例如,这些参数可以设置工作器线程数量、大核心和小核心的工作器线程亲和性、GPU 保真度选项以及帧缓冲区分辨率。在 Unity Engine 中,游戏开发者可以通过使用 Adaptive Performance 插件更改 Quality Settings 来调整工作负载。对于 Unreal Engine,请使用可扩缩设置来动态调整质量级别。

当设备接近不安全的热状态时,您的游戏可以通过借助这些参数降低工作负载来避免受到限制。为避免受到限制,您应监控设备的热状态并主动调整游戏引擎工作负载。设备过热后,工作负载必须降至可持续的性能水平以下,以便进行散热。在热余量降低到更安全的级别后,游戏可以再次提高质量设置,但要确保找到一个可持续的质量级别以获得最佳游戏时间。

您可以通过轮询 getThermalHeadroom 方法来监控设备的热状态。此方法可预测设备可以在不过热的情况下保持当前性能水平多长时间。如果时间低于运行工作负载所需的时间量,您的游戏应将工作负载降低到可持续水平。例如,游戏可以切换到较小的核心、降低帧速率或降低保真度。

ADPF Thermal API 预集成
图 1.未主动监控 getThermalHeadroom 的热余量
ADPF Thermal API 集成后
图 2. 主动监控“getThermalHeadroom”的热余量

获取热管理经理

若要使用 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);

在热状态发生变化时收到通知

您也可以避免轮询 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 的完整指南,请参阅自适应 Codelab 部分的集成 Thermal API 部分。

热余量指南

您可以通过轮询 getThermalHeadroom 方法来监控设备的热状态。此方法可预测设备在达到 THERMAL_STATUS_SEVERE 之前可以保持当前性能水平多长时间。例如,如果 getThermalHeadroom(30) 返回 0.8,则表示在 30 秒内,余量预计会达到 0.8(即离严重限制的距离为 0.2),即 1.0。如果时间低于运行工作负载所需的时间,您的游戏应将工作负载降低到可持续的水平。例如,游戏可以降低帧速率、降低保真度或减少网络连接工作。

热状态和含义

Thermal API 的设备限制

由于 Thermal API 在旧款设备上实现了 Thermal API,因此存在一些已知的限制或附加要求。相关限制和解决办法如下:

  • 请勿过于频繁地调用 GetThermalHeadroom() API。这样做会导致 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 对旧设备上的支持情况的启发法示例