2016년 10월 12일 수요일

[안드로이드] Doze 모드

Doze 모드 최적화

안드로이드 6.0(API 23)부터 배터리를 절약하기 위해 Doze 모드가 추가되었다. 사용자가 휴대폰을 사용하고 있지 않다고 판단되면, 시스템은 모든 앱의 배터리를 많이 잡아먹는 백그라운드 작업과 네트워킹을 일시 중단시킨다. Doze 모드는 타겟 API가 23 이하의 앱이더라도 동일하게 적용되므로, Doze 모드에서의 앱 동작을 확인해봐야 한다.

Doze 모드 이해하기

디바이스에 전원공급이 없고, 스크린이 꺼진 채로 아무 움직임 없이 일정 시간이 지나면, 디바이스는 Doze 모드로 진입하게 된다. Doze 모드에 진입하게 되면, 시스템은 배터리를 절약하기 위해 모든 앱의 네트워크 사용과 CPU를 과도하게 이용하는 백그라운드 서비스, Sync, 기본 알람까지 제한한다.
주기적으로, 시스템은 Doze모드에서 깨어나, 모든 앱이 미뤄뒀던 작업을 완료할 수 있는 Maintenance Window라 불리는 짧은 시간을 가진다. 이 짧은 시간동안, 시스템은 Doze 모드에 진입하면서 멈췄던 작업들을 다시 시작하도록 수행한다.
디바이스의 화면이 켜지거나, 전원공급이 시작되면 앱은 Doze 모드에서 벗어나 원래대로 모든 작업을 수행하게 된다.
6.0 Doze
최근, 7.0(API 24)에서는 디바이스에 전원공급이 없고 화면만 꺼져있으면, 디바이스가 움직이더라도 Doze 모드로 진입한다. 그리고 Doze 모드가 2단계로 세분화되었다.
1단계에서는 네트워크 엑세스, Sync, Job 스케쥴링 정지, 2단계에서는 GPS, Wifi 스캐닝, wake lock 등이 제한된다.
7.0 Doze

Doze 모드에서 제한되는 동작

  • 네트워크 엑세스
  • Wake Lock
  • AlarmManager의 기본 알람
    • setAndAllowWhileIdle() / setExactAndAllowWhileIdle() 메서드를 이용한 알람은 Doze모드에서도 받을 수 있다.
    • setAlarmClock() 메서드를 이용한 알람은 정상적으로 동작한다. 이 알람이 울리기 전에, 시스템은 Doze 모드를 빨리 빠져나온다.
  • Wifi 스캐닝
  • Sync Adapter 동작
  • Job Scheduler 동작

Doze 모드 적용

Doze 모드에 대한 영향은 앱마다 다 다를것이다. 대부분의 앱들은 아무런 변경 없이도 Doze 모드 주기안에 잘 동작할 것이다. 하지만, 네트워크, 알람, Job, Sync 를 이용하고 있다면 Doze 모드를 확인해 볼 필요가 있다. 이 앱들은 각maintenence window 동안에 효율적으로 동작하도록 만들어야 한다.
AlarmManager의 경우, 기존에 있던 API 메서드를 이용하면, Doze 모드에서는 알람이 정확하게 울리지 않는다. 그래서 Doze 모드에서도 알람이 제대로 동작하도록 하려면 6.0(API 23)에서 추가된setAndAllowWhileIdle()setExactAndAllowWhileIdle() 메서드를 이용해야 한다.
앱이 실시간으로 연결을 유지하며 메시지를 받을 필요가 있다면, Google Cloud Messageing 을 고려해본다.

Doze 모드 감지
브로드캐스트 리시버를 등록하고, PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED 액션을 수신하도록 등록하면, Doze 모드일 때, 디바이스가 대기 상태로 변경되며, 해당 액션이 발생하게 된다.
if (Build.VERSION.SDK_INT >= VERSION_CODES.M) {
    registerReceiver(mDeviceIdleModeReceiver, new IntentFilter(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED));
}

App Standby 이해하기

App Standby는 사용자가 앱을 이용하지 않을 때, 앱이 대기상태인지를 결정한다. 시스템은 일정시간 동안 앱에 아무런 동작이 없고, 다음의 상황이 아닐 때, 앱을 대기상태로 인지한다.
  • 사용자가 명시적으로 앱을 실행
  • 앱이 현재 포그라운드 프로세스를 가지고 있음
  • 사용자가 Notification 영역을 보고있고, 그 영역에 Notification을 출력해야 할 때
디바이스가 전원공급이 시작되면, 시스템은 이 앱들을 standby 상태로부터 해제하고, 앱의 네트워크 액세스, 스케쥴링 등 제한했던 동작을 수행하도록 한다.

디바이스가 대기 상태일 때, GCM을 이용해 인터렉션하기

GCM은 클라우드와 하나의 영구적인 연결을 유지하여, 실시간 메시징이 필요한 모든 앱들이 이 연결을 공유할 수 있도록 한다. 연결을 공유하는 이 기법은 앱마다 자신만의 연결을 유지하는 것보다 배터리를 훨씬 절약할 수 있도록 한다. 이러한 이유때문에, 구글은 실시간 메시징이 필요하다면, GCM을 이용하는걸 추천한다.
GCM 메시지의 우선순위를 높여주게 되면, 디바이스가 Doze 모드에 있거나, 앱이 Standby 상태 이더라도 네트워크에 연결할 수 있도록 수행한다. 동작 수행 후, 다시 대기 상태로 돌아간다. 즉, GCM 메시지는 Doze 모드나 App의 상태에 영향을 받지 않고, 효율적으로 상호작용 할 수 있다.

Doze & App Standby 모드 테스트하기

Doze 모드 테스트

1.앱을 실행하고, 아무 동작도 하지 않는다.
2.디바이스 스크린을 끈다.(앱은 그대로 Active 상태로 둔다.)
3.다음 명령어를 command에 입력하여 adb를 이용해 강제로 Doze모드 발생 상태를 만든다. 단, 디바이스의 상태가 변할 때까지 두번째 문장은 계속 실행한다.
$ adb shell dumpsys battery unplug
$ adb shell dumpsys deviceidle step
4.디바이스를 다시 활성화시킨 후에 앱이 정상동작 하는지 확인한다.

App Standby 모드 테스트

1.앱을 실행하고, 아무 동작도 하지 않는다.
2.command에 다음 명령어를 실행하여 강제로 앱을 Standby 상태로 만든다.
$ adb shell dumpsys battery unplug
$ adb shell am set-inactive <packageName> true
3.command에 다음의 명령어를 실행하여 앱을 깨운다.
$ adb shell ab set-inactive <packageName> false
$ adb shell ab get-inactive <packageName>
4.앱이 원상태로 돌아온 후에 정상동작 하는지 확인한다. 특히, Notification이나 Job 등이 생각한대로 동작하는지 확인한다.

댓글 없음:

댓글 쓰기