已发布:
Android 11(API 级别 30)- Thermal API
Android 12(API 级别 31)- NDK API
(预览版)Android 15 (DP1) - getThermalHeadroomThresholds()
应用的潜在性能受设备热状态的限制,热状态可能会因天气、近期使用情况以及设备热设计等特性而异。设备只能维持较高的 在一段有限的时间里确保性能,然后才会受到温控。实现的关键目标是在不超出热限制的情况下实现性能目标。Thermal API 让这一切无需您 进行设备特定的优化此外,在调试性能时 设备热状态是否会限制性能 非常重要。此外,在调试性能问题时 了解设备的热状态是否限制了性能 非常重要。
游戏引擎通常具有运行时性能参数,可以调整引擎对设备施加的工作负载。例如,这些参数可以设置 工作器线程数、大小核心的工作器线程亲和性、 GPU 保真度选项和帧缓冲区分辨率。在 Unity Engine 中,游戏 开发者可以通过更改 设置 使用 Adaptive Performance 插件。 对于 Unreal Engine,请使用可伸缩性设置来调整 动态地调整质量级别。
当设备接近不安全的热状态时,您的游戏可以通过借助这些参数降低工作负载来避免受到限制。为避免受到限制,您应监控设备的热状态并主动调整游戏引擎工作负载。一旦设备过热,工作负载必须 降至可持续的性能水平以下,以便散热。更新后 热余量降低到更安全的水平,游戏可以提高 但务必找到可持续的质量水平 以获得最佳游戏时间。
您可以通过轮询 getThermalHeadroom
方法来监控设备的热状态。此方法可预测设备可以保持当前状态多长时间
性能水平不会过热如果时间低于运行工作负载所需的时间量,您的游戏应将工作负载降低到可持续水平。例如,游戏可以切换到较小的核心、降低帧速率或降低保真度。
![ADPF Thermal API 预集成](https://developer.android.google.cn/static/games/optimize/adpf/images/adpf_thermal_pre-integration.png?authuser=9&hl=zh-cn)
![ADPF Thermal API 集成后](https://developer.android.google.cn/static/games/optimize/adpf/images/adpf_thermal_post-integration.png?authuser=9&hl=zh-cn)
获取热管理器
要使用 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
命中之前轮询 thermalHeadroom
特定级别(例如: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),请查看集成 自适应 Codelab 中的 Thermal API 部分 部分。
热余量准则
您可以通过轮询 getThermalHeadroom
方法来监控设备的热状态。此方法可预测设备可以保持当前状态多长时间
达到 THERMAL_STATUS_SEVERE
之前的效果水平。
例如,如果 getThermalHeadroom(30)
返回 0.8,则表示
秒,则余量预计将达到 0.8,此时距离为 0.2
或 1.0。如果用时少于
运行工作负载,那么您的游戏应将工作负载减少到可持续
。例如,游戏可能会降低帧速率、保真度或
减少网络连接工作量
热状态和含义
- 如果设备没有温控调频:
<ph type="x-smartling-placeholder">
- </ph>
THERMAL_STATUS_NONE
- 会限制性能,但对性能没有显著影响: <ph type="x-smartling-placeholder">
- 受到重大限制,影响性能: <ph type="x-smartling-placeholder">
Thermal API 的设备限制
由于 Thermal API 存在一些已知的限制或其他要求, Thermal API 在旧款设备上的实现。局限性和方法 解决方法如下:
- 请勿过于频繁地调用
GetThermalHeadroom()
API。这样做会 会导致 API 返回 NaN。每秒最多调用一次。 - 如果
GetThermalHeadroom()
的初始值为 NaN,则表示 API 不是 设备上可用 - 如果
GetThermalHeadroom()
返回较高值(例如:0.85 或更高),并且GetCurrentThermalStatus()
仍返回THERMAL_STATUS_NONE
,状态为 可能未更新。使用启发法估算正确的温控调频 状态,或者直接使用getThermalHeadroom()
,而不使用getCurrentThermalStatus()
。
启发词语示例:
- 检查 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.
}
}
}
示意图:
<ph type="x-smartling-placeholder">