Выпущенный :
Android 11 (уровень API 30) – тепловой API
Android 12 (уровень API 31) — API NDK
(Предварительная версия) Android 15 (DP1) — getThermalHeadroomThresholds()
Потенциальная производительность вашего приложения ограничена тепловым состоянием устройства, которое может варьироваться в зависимости от таких характеристик, как погода, недавнее использование и тепловая конструкция устройства. Устройства могут поддерживать высокий уровень производительности только в течение ограниченного периода времени, прежде чем произойдет термическое регулирование. Ключевой целью вашей реализации должно быть достижение целевых показателей производительности без превышения температурных ограничений. Thermal API делает это возможным без необходимости оптимизации конкретного устройства. Кроме того, при устранении проблем с производительностью важно знать, ограничивает ли производительность тепловое состояние вашего устройства.
Игровые движки обычно имеют параметры производительности во время выполнения, которые могут регулировать рабочую нагрузку, которую движок возлагает на устройство. Например, эти параметры могут устанавливать количество рабочих потоков, привязку рабочих потоков для больших и малых ядер, параметры точности графического процессора и разрешения кадрового буфера. В Unity Engine разработчики игр могут регулировать рабочую нагрузку, изменяя настройки качества с помощью плагина Adaptive Performance . В Unreal Engine используйте настройки масштабируемости для динамической настройки уровней качества.
Когда устройство приближается к небезопасному тепловому состоянию, ваша игра может избежать регулирования, уменьшив рабочую нагрузку с помощью этих параметров. Чтобы избежать троттлинга, следует следить за тепловым состоянием устройства и заранее корректировать нагрузку игрового движка. Когда устройство перегревается, рабочая нагрузка должна упасть ниже устойчивого уровня производительности, чтобы обеспечить рассеивание тепла. После того, как запас температуры снизится до более безопасного уровня, игра может снова повысить настройки качества, но обязательно найдите устойчивый уровень качества для оптимального игрового времени.
Вы можете отслеживать тепловое состояние устройства, опрашивая метод getThermalHeadroom
. Этот метод предсказывает, как долго устройство сможет сохранять текущий уровень производительности без перегрева. Если время меньше, чем необходимое для выполнения рабочей нагрузки, ваша игра должна снизить рабочую нагрузку до устойчивого уровня. Например, игра может перейти на меньшие ядра, снизить частоту кадров или снизить точность воспроизведения.
Приобретите Термальный менеджер
Чтобы использовать Thermal API, сначала вам необходимо приобрести Thermal Manager.
С++
AThermalManager* thermal_manager = AThermal_acquireManager();
Ява
PowerManager powerManager = (PowerManager)this.getSystemService(Context.POWER_SERVICE);
Прогнозируйте тепловой запас на x секунд вперед для большего контроля
Вы можете попросить систему спрогнозировать температуру на x секунд вперед с учетом текущей рабочей нагрузки. Это дает вам более детальный контроль и больше времени для реагирования за счет снижения рабочей нагрузки, чтобы предотвратить срабатывание теплового регулирования.
Результат варьируется от 0,0f (без регулирования, THERMAL_STATUS_NONE
) до 1,0f (сильное регулирование, THERMAL_STATUS_SEVERE
). Если в ваших играх разные уровни качества графики, вы можете следовать нашим рекомендациям по температурному запасу .
С++
float thermal_headroom = AThermal_getThermalHeadroom(10);
ALOGI("ThermalHeadroom in 10 sec: %f", thermal_headroom);
Ява
float thermalHeadroom = powerManager.getThermalHeadroom(10);
Log.d("ADPF", "ThermalHeadroom in 10 sec: " + thermalHeadroom);
Альтернативно, для уточнения можно полагаться на температурный статус.
Каждая модель устройства может быть спроектирована по-разному. Некоторые устройства могут лучше распределять тепло и, таким образом, выдерживать более высокий тепловой запас до дросселирования. Если вы хотите прочитать упрощенную группу диапазонов температурного запаса, вы можете проверить тепловой статус, чтобы понять значение температурного запаса на текущем устройстве.
С++
AThermalStatus thermal_status = AThermal_getCurrentThermalStatus(thermal_manager);
ALOGI("ThermalStatus is: %d", thermal_status);
Ява
int thermalStatus = powerManager.getCurrentThermalStatus();
Log.d("ADPF", "ThermalStatus is: " + thermalStatus);
Получайте уведомления при изменении теплового статуса
Вы также можете избежать опроса thermalHeadroom
до тех пор, пока thermalStatus
не достигнет определенного уровня (например: THERMAL_STATUS_LIGHT
). Для этого вы можете зарегистрировать обратный вызов, чтобы система уведомляла вас при каждом изменении статуса.
С++
int result = AThermal_registerThermalStatusListener(thermal_manager, callback);
if ( result != 0 ) {
// failed, check whether you have previously registered callback that
// hasn’t been unregistered
}
Ява
// 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);
Не забудьте удалить прослушиватель, когда закончите.
С++
int result = AThermal_unregisterThermalStatusListener(thermal_manager, callback);
if ( result != 0 ) {
// failed, check whether the callback has been registered previously
}
Ява
powerManager.removeThermalStatusListener(listener);
Очистка
Когда вы закончите, вам нужно будет очистить приобретенный вами Thermal_manager. Если вы используете Java, ссылка PowerManager может быть автоматически удалена за вас. Но если вы используете Java API через JNI и сохранили ссылку, не забудьте очистить ссылку!
С++
AThermal_releaseManager(thermal_manager);
Полное руководство по реализации Thermal API в собственной игре на C++ с использованием как C++ API (NDK API), так и Java API (через JNI), см. в разделе «Интеграция Thermal API» в разделе «Кодовая лаборатория адаптивности» .
Рекомендации по температурному запасу
Вы можете отслеживать тепловое состояние устройства, опрашивая метод getThermalHeadroom
. Этот метод предсказывает, как долго устройство сможет поддерживать текущий уровень производительности до достижения THERMAL_STATUS_SEVERE
. Например, если getThermalHeadroom(30)
возвращает 0,8, это означает, что через 30 секунд запас, как ожидается, достигнет 0,8, где расстояние до серьезного регулирования составляет 0,2, или 1,0. Если время меньше, чем необходимое для выполнения рабочей нагрузки, ваша игра должна снизить рабочую нагрузку до устойчивого уровня. Например, игра может снизить частоту кадров, снизить качество воспроизведения или уменьшить нагрузку на сетевое подключение.
Термические статусы и значение
- Если устройство не имеет термического регулирования:
- Некоторое троттлинг, но существенного влияния на производительность не оказывает:
- Значительное регулирование, влияющее на производительность:
Ограничения устройств Thermal API
Существуют некоторые известные ограничения или дополнительные требования Thermal API, связанные с реализацией Thermal API на старых устройствах. Ограничения и способы их обхода следующие:
- Не вызывайте API
GetThermalHeadroom()
слишком часто. В результате API вернет NaN. Вы должны вызывать его не чаще одного раза в секунду. - Если начальное значение
GetThermalHeadroom()
равно NaN, API недоступен на устройстве. - Если
GetThermalHeadroom()
возвращает высокое значение (например: 0,85 или больше), аGetCurrentThermalStatus()
по-прежнему возвращаетTHERMAL_STATUS_NONE
, статус, скорее всего, не обновится. Используйте эвристику для оценки правильного состояния теплового регулирования или просто используйтеgetThermalHeadroom()
безgetCurrentThermalStatus()
.
Пример эвристики:
- Убедитесь, что Thermal API поддерживается.
isAPISupported()
проверяет значение первого вызоваgetThermalHeadroom
, чтобы убедиться, что оно не равно 0 или NaN, и пропускает использование API, если первое значение равно 0 или NaN. - Если
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.
}
}
}
Диаграмма: