Выпущенный :
Android 11 (уровень API 30) - Thermal API
Android 12 (уровень API 31) — API NDK
(Предварительная версия) Android 15 (DP1) - getThermalHeadroomThresholds()
Потенциальная производительность вашего приложения ограничена тепловым состоянием устройства, которое может меняться в зависимости от таких характеристик, как погода, недавнее использование и тепловая конструкция устройства. Устройства могут поддерживать высокий уровень производительности лишь ограниченное время, после чего происходит снижение производительности из-за перегрева. Ключевой целью вашей реализации должно быть достижение целевых показателей производительности без превышения тепловых ограничений. Thermal API позволяет это сделать без необходимости оптимизации, специфичной для конкретного устройства. Кроме того, при отладке проблем с производительностью важно знать, ограничивает ли производительность ваше устройство его тепловое состояние.
Игровые движки обычно имеют параметры производительности во время выполнения, которые позволяют регулировать нагрузку, создаваемую движком на устройстве. Например, эти параметры могут устанавливать количество рабочих потоков, привязку рабочих потоков к большим и малым ядрам, параметры качества GPU и разрешение кадрового буфера. В Unity Engine разработчики игр могут регулировать нагрузку, изменяя параметры качества с помощью плагина Adaptive Performance . В Unreal Engine для динамической настройки уровней качества используются параметры масштабируемости .
Когда устройство приближается к опасному температурному состоянию, ваша игра может избежать снижения производительности, уменьшив нагрузку с помощью этих параметров. Чтобы избежать снижения производительности, следует отслеживать температурное состояние устройства и заблаговременно корректировать нагрузку на игровой движок.
Когда устройство перегревается, нагрузка должна снизиться ниже допустимого уровня производительности, чтобы рассеять тепло. После того, как запас по температуре снизится до безопасного уровня, игра может снова повысить настройки качества, но обязательно найдите оптимальный уровень качества для комфортной игры.
Вы можете отслеживать тепловое состояние устройства, опрашивая метод 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(0);
ALOGI("ThermalHeadroom: %f", thermal_headroom);
Java
float thermalHeadroom = powerManager.getThermalHeadroom(0);
Log.d("ADPF", "ThermalHeadroom: " + 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 может быть автоматически удалена сборщиком мусора. Но если вы используете Java API через JNI и сохранили ссылку, не забудьте удалить её!
C++
AThermal_releaseManager(thermal_manager);
Полное руководство по реализации Thermal API в нативной игре на C++ с использованием как API C++ (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. Эти ограничения и способы их преодоления описаны ниже:
- Не вызывайте функцию
GetThermalHeadroom()слишком часто. В противном случае функция вернетNaN. Не следует вызывать ее чаще, чем раз в 10 секунд. - Избегайте вызовов из нескольких потоков, так сложнее обеспечить частоту вызовов, и это может привести к тому, что 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.
}
}
}
Диаграмма: