안드로이드 Q - Thermal API로 발열 상태 모니터링

안드로이드 Q에서 디바이스의 발열 상태를 알 수 있는 API를 제공하기 시작하였습니다. 앱은 PowerManager에 Thermal Status Listener를 등록함으로써 디바이스의 발열 상태 변화를 알 수 있습니다. 발열 상태는 CRITICAL, EMERGENCY, LIGHT, NONE 등 총 7개의 상태가 있습니다.

앱이 디바이스의 Thermal status를 알 수 있도록 API를 제공하는 이유는, 디바이스의 온도가 매우 높아져 CPU, GPU의 클럭이 낮아지는 경우 앱이 원하는 퍼포먼스를 낼 수 없기 때문입니다. 만약 온도가 매우 높아졌다면, 앱은 저하된 디바이스 성능에 맞춰 원활한 퍼포먼스를 유지하기 위해서 작업을 줄여야 합니다. 예를 들어, 스트리밍 앱은 해상도를 낮춰 네트워크 트래픽을 낮출 수 있고, 카메라 앱은 이미지 보정을 줄일 수 있습니다. 또한, 게임 앱은 프레임 속도를 조절하여 저하된 성능에 원하는 퍼포먼스를 낼 수 있습니다.

이런 동작은 디바이스의 시스템을 보호하려고 유도하는 것일 수 있지만, 앱 또한, 실행 중인 앱의 퍼포먼스 관점에서 매우 중요할 수 있습니다. Q 이전 버전의 디바이스에서 삼성, 화웨이 등의 제조사는 개별적으로 제공하는 API가 있었거나, 아니면 제조사만 사용하는 API가 있었을지 모릅니다.

하지만, Q 이후부터는 AOSP(Android Open Source Project) 자체적으로 Public API를 제공합니다. 현재 Android Q 버전의 PIXEL 폰에서 이 API는 정상적인 동작을 보장합니다. 앞으로, 다른 제조사에서도 Thermal API에 대한 동작이 지원될 것 같습니다.

이 글을 쓰는 현재는, 안드로이드 Q 베타를 진행하고 있고 SDK API까지만 공개된 상태입니다. 이런 정보들로 간단히 Thermal Status Listener를 등록하여 상태를 모니터링하는 코드를 구현해보겠습니다.

이 글에서 소개하는 코드는 모두 코틀린으로 작성되었습니다.

Thermal Status

아래와 같이 Thermal 상태는 7개입니다. Android Developer - PowerManager에서 상태와 의미를 가져왔습니다.

  • THERMAL_STATUS_NONE: Not under throttling.
  • THERMAL_STATUS_LIGHT: Light throttling where UX is not impacted.
  • THERMAL_STATUS_MODERATE: Moderate throttling where UX is not largely impacted.
  • THERMAL_STATUS_SEVERE: Severe throttling where UX is largely impacted.
  • THERMAL_STATUS_CRITICAL: Platform has done everything to reduce power.
  • THERMAL_STATUS_EMERGENCY: Key components in platform are shutting down due to thermal condition. Device functionalities will be limited.
  • THERMAL_STATUS_SHUTDOWN: Need shutdown immediately.

맨 위의 NONE이 온도가 가장 낮은 것이고, 아래로 갈 수록 온도가 높은 상태입니다.

현재 Thermal Status 가져오기

PowerManager.currentThermalStatus는 현재의 Thermal status를 리턴하는 API입니다.

val powerManager = getSystemService(Context.POWER_SERVICE) as? PowerManager
Log.d(TAG, "get current Thermal status: ${powerManager?.currentThermalStatus}")

Thermal Listener 등록

아래와 같이 PowerManager에 Listener를 등록하여 Thermal Status 변화를 받을 수 있습니다.

val powerManager = getSystemService(Context.POWER_SERVICE) as? PowerManager
powerManager?.addThermalStatusListener { status ->
    when (status) {
        PowerManager.THERMAL_STATUS_SHUTDOWN -> {
            Log.d(TAG, "THERMAL_STATUS_SHUTDOWN")
        }
        PowerManager.THERMAL_STATUS_EMERGENCY -> {
            Log.d(TAG, "THERMAL_STATUS_EMERGENCY")
        }
        PowerManager.THERMAL_STATUS_CRITICAL -> {
            Log.d(TAG, "THERMAL_STATUS_CRITICAL")
        }
        PowerManager.THERMAL_STATUS_SEVERE -> {
            Log.d(TAG, "THERMAL_STATUS_SEVERE")
        }
        PowerManager.THERMAL_STATUS_MODERATE -> {
            Log.d(TAG, "THERMAL_STATUS_MODERATE")
        }
        PowerManager.THERMAL_STATUS_LIGHT -> {
            Log.d(TAG, "THERMAL_STATUS_LIGHT")
        }
        PowerManager.THERMAL_STATUS_NONE -> {
            Log.d(TAG, "THERMAL_STATUS_NONE")
        }
    }
}

리스터로 콜백을 받을 때 Main thread가 콜백을 해 줍니다. 만약 다른 스레드에서 동작하길 원한다면 아래 API를 사용해야 할 것 같습니다. 테스트 해보진 않았습니다. 좀 더 자세한 것은 Android Developer - PowerManager에서 확인해주세요.

void addThermalStatusListener(Executor executor, PowerManager.OnThermalStatusChangedListener listener)

Thermal Listener 해제

리스너를 해제할 때는 등록할 때 사용한 OnThermalStatusChangedListener 객체를 인자로 전달해줘야 합니다.

다음과 같이 리스너 객체를 멤버 변수로 선언하고, 이 객체를 등록할 때와 해제할 때 사용하시면 됩니다.

val powerManager = getSystemService(Context.POWER_SERVICE) as? PowerManager
val thermalStatusListener =
        PowerManager.OnThermalStatusChangedListener { status ->
            when (status) {
              //....
            }
        }

powerManager?.addThermalStatusListener(thermalStatusListener)
powerManager?.removeThermalStatusListener(thermalStatusListener)

정리

안드로이드 Q에서 제공되는 Thermal Status API에 대해서 알아보고, 간단히 구현도 해보았습니다. API에 대한 자세한 내용은 Android Developer에서 확인하실 수 있습니다.

참고

Loading script...

Related Posts

codechachaCopyright ©2019 codechacha