출시됨:
Android 11 (API 수준 30) - Thermal API
Android 12 (API 수준 31) - NDK API
(미리보기) Android 15 (DP1) - getThermalHeadroomThresholds()
앱은 기기의 열 상태에 따라 잠재적으로 성능이 제한되며, 기기의 열 상태는 날씨, 최근 사용량, 기기의 열 관련 설계와 같은 특성에 따라 달라질 수 있습니다. 기기는 온도로 인해 성능이 제한되기 전에 제한된 시간 동안만 높은 수준의 성능을 유지할 수 있습니다. 구현의 주요 목표는 열 제한을 초과하지 않고 성능 목표를 달성하는 것입니다. Thermal API를 사용하면 기기별 최적화가 필요하지 않습니다. 또한, 성능 문제를 디버그할 때는 기기의 열 상태가 성능을 제한하는지 파악하는 것이 중요합니다.
게임 엔진에는 일반적으로 엔진이 기기에 부여하는 워크로드를 조정할 수 있는 런타임 성능 매개변수가 있습니다. 예를 들어, 이러한 매개변수는 작업자 스레드 수, 큰 코어와 작은 코어의 작업자 스레드 어피니티, GPU 충실도 옵션, 프레임 버퍼 해상도를 설정할 수 있습니다. Unity 엔진에서 게임 개발자는 Adaptive Performance plugin을 사용하여 Quality Settings을 변경하여 워크로드를 조정할 수 있습니다. Unreal Engine의 경우 확장성 설정을 사용하여 품질 수준을 동적으로 조정합니다.
기기가 안전하지 않은 열 상태에 도달하면 게임은 이러한 매개변수를 통해 워크로드를 줄여 성능이 제한되는 상황을 피할 수 있습니다. 제한 상황을 피하려면 기기의 열 상태를 모니터링하고 게임 엔진 워크로드를 미리 조정해야 합니다.
기기가 일단 과열되면 열을 방출하기 위해 워크로드가 지속 가능한 성능 수준 아래로 떨어져야 합니다. 열 헤드룸이 더 안전한 수준으로 감소한 후 게임은 품질 설정을 다시 높일 수 있지만 최적의 플레이 시간을 위해 지속 가능한 품질 수준을 찾아야 합니다.
getThermalHeadroom 메서드를 폴링하여 기기의 열 상태를 모니터링할 수 있습니다. 이 메서드는 기기가 과열되지 않고 얼마나 오랫동안 현재 성능 수준을 유지할 수 있는지를 예측합니다. 시간이 워크로드를 실행하는 데 필요한 시간보다 적으면 게임에서 지속 가능한 수준으로 워크로드를 줄여야 합니다. 예를 들어 게임은 더 작은 코어로 전환하거나 프레임 속도를 낮추거나 충실도를 낮출 수 있습니다.
Thermal Manager 가져오기
Thermal API를 사용하려면 먼저 Thermal Manager를 가져와야 합니다.
C++
AThermalManager* thermal_manager = AThermal_acquireManager();
자바
PowerManager powerManager = (PowerManager)this.getSystemService(Context.POWER_SERVICE);
열 헤드룸 쿼리
시스템에 현재 열 헤드룸을 요청할 수 있습니다. 이렇게 하면 워크로드가 열 제한에 얼마나 가까운지 알 수 있습니다. 또한 API를 사용하면 현재 워크로드로 x초 후의 온도를 예측할 수 있습니다. 이렇게 하면 애플리케이션이 응답하는 데 더 많은 시간이 걸리지만 현재 열 상태를 사용하는 것보다 정확도가 떨어집니다.
결과는 0.0f (제한 없음,
THERMAL_STATUS_NONE)
~ 1.0f (심한 제한,
THERMAL_STATUS_SEVERE)입니다.
게임에 다양한 그래픽 품질 수준이 있는 경우
열 헤드룸 가이드라인을 따를 수 있습니다.
C++
float thermal_headroom = AThermal_getThermalHeadroom(0);
ALOGI("ThermalHeadroom: %f", thermal_headroom);
자바
float thermalHeadroom = powerManager.getThermalHeadroom(0);
Log.d("ADPF", "ThermalHeadroom: " + thermalHeadroom);
또는 열 상태를 사용하여 명확히 하기
각 기기 모델은 다르게 설계될 수 있습니다. 일부 기기는 열을 더 잘 분산할 수 있으므로 제한되기 전에 더 높은 열 헤드룸을 견딜 수 있습니다. 열 헤드룸 범위의 단순화된 그룹화를 읽으려면 열 상태를 확인하여 현재 기기의 열 헤드룸 값을 파악할 수 있습니다.
C++
AThermalStatus thermal_status = AThermal_getCurrentThermalStatus(thermal_manager);
ALOGI("ThermalStatus is: %d", thermal_status);
자바
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
}
자바
// 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
}
자바
powerManager.removeThermalStatusListener(listener);
정리
완료되면 가져온 thermal_manager를 정리해야 합니다. 자바를 사용하는 경우 PowerManager 참조가 자동으로 가비지 수집될 수 있습니다. 하지만 JNI를 통해 자바 API를 사용하고 참조를 유지한 경우 참조를 정리해야 합니다.
C++
AThermal_releaseManager(thermal_manager);
C++ API (NDK API)와 자바 API (JNI를 통해)를 모두 사용하여 네이티브 C++ 게임에 Thermal API를 구현하는 방법에 관한 전체 가이드는 Thermal API 통합 섹션의 적응성 Codelab 섹션을 참고하세요.
열 헤드룸 가이드라인
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을 반환하는 경우 상태가 업데이트되지 않을 수 있습니다. 휴리스틱을 사용하여 올바른 열 제한 상태를 추정하거나getCurrentThermalStatus()없이getThermalHeadroom()을 사용하세요.
휴리스틱 예시:
- 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.
}
}
}
다이어그램: