본문 바로가기
[클라이언트]/[Android Kotlin]

[AlarmManager] - Doze, App StandBy, 배터리 최적화, Idle 상태에 대해

by Hevton 2023. 5. 7.
반응형

 

 

Doze 모드, App Standby, 배터리 최적화, Idle 상태, 백그라운드 실행 제한 등

정책들이 날이 갈수록 새로 생겨나면서, 저희 같은 서비스를 운영하는 사람들에게는 이만 저만 어려운 점이 많습니다

 

관련 정보와 솔루션을 명확하게 정리하여 여러분들의 시간을 절약시키겠습니다.!

이번 글에서는 기기의 여러 상태와, 그에 대응할 수 있는 AlarmManager의 여러 함수들에 대해 설명하겠습니다.

 


 

 

안드로이드 공식 문서에서 잠자기 및 앱 대기모드에 대한 설명을 진행하고 있습니다.

이러한 기기 상황에 대해서 아래와 같이 정리하겠습니다.

 

 

Doze 모드 (Android 6.0)

- AlarmManager 작동 안할 수 있음. 단 setExactAndAllowWhileIde(), setAlarmClock() 예외

- JobScheduler 딜레이됨: WorkManager도 영향을 받을 수 있음

 

App Standby (Android 6.0)

- FCM high priority 아니면 지연될 수 있음

- JobScheduler 딜레이됨

 

 

배터리 최적화 (Android 6.0)

- Doze/App Standby와 함께 동작하는 프레임워크로, 앱의 백그라운드 실행을 자동으로 조절함

- 백그라운드 강제 종료될 수 있음

 

백그라운드 실행 제한 (Android 8.0)

- 백그라운드에서는 포그라운드 서비스만 실행 가능

 

 

Idle 상태

- Doze의 세부 단계이자, 가장 제약이 강함 (Light Doze -> Deep Doze)

- JobSchedluer 대기, Alarm 무시, setAlarmClock() 예외

 

 

정보를 간단하게 표로 정리하겠습니다.

기능도입 버전적용 대상제한 내용 예외
Doze 모드 Android 6.0 전체 기기 알람, 네트워크, 작업 제한 Maintenance Window, High-priority FCM
App Standby Android 6.0 사용 안 하는 앱 백그라운드 네트워크/작업 제한 사용자 상호작용 시 해제
배터리 최적화 Android 6.0+ 모든 앱 백그라운드 작업 제한 예외 앱으로 설정 가능
Idle 상태 Android 6.0+ 전체 기기 단계별 제한 강화 없음
백그라운드 실행 제한 Android 8.0~ 백그라운드 앱 서비스/브로드캐스트 제한 ForegroundService 사용

 

 

그럼 이러한 상황들을, '포그라운드 서비스' 로 구현한다면 모두 우회할 수 있을지? 에 대한 생각도 해볼 수 있는데요

일부는 그렇지만 모두는 그렇지 않습니다.

 

제한 정책 포그라운드 서비스로 우회 가능? 설명
Doze 모드 가능 Doze 상태에서도 포그라운드 서비스는 네트워크 접근, 작업 수행이 가능함
App Standby 가능 사용자가 오랫동안 앱을 쓰지 않았더라도, 포그라운드 서비스는 동작 가능
배터리 최적화 제한적  포그라운드 서비스는 최적화 대상이어도 제한을 거의 받지 않음
백그라운드 실행 제한 가능 백그라운드 서비스는 제한되지만, 포그라운드 서비스는 예외
알람/JobScheduler 제한 제한적 일부 제한은 여전히 있음 (e.g. 정확한 시간 알람은 별도 처리 필요)

 

배터리 최적화 제외

만약 배터리 최적화를 통해서 서비스가 강제 종료 되는 것을 방지하고 싶다면

배터리 최적화 예외 방법에 대해서는 제 경험상 두 가지 방법이 있습니다.

 

1. 사용자를 직접 설정으로 이동시킴

-> 이는 Settgins. 인텐트를 사용하여 직접 이동시켜서, 사용자분들에게 '배터리 최적화' 옵션에 들어가서 직접 '설정 안함'을 요청드려야 해서 사용자의 만족도가 떨어질 수 있습니다.

 

2. 다이얼로그를 띄워서 간단하게 권한 요청

-> 이는 REQUEST_IGNORE_BATTERY_OPTIMIZATIONS 를 가진 상태에서, 런타임으로 권한을 요청할 수 있지만.. Google의 공식 문서에 따르면 '정말 필요한 핵심 기능에 관한 동작이 아니라면 앱이 정지될 수 있다' 라고 합니다.

 

알람/JobScheduler 제한에 대해

WorkManager도 내부적으로 JobScheduler를 사용하며, JobScheduler는 기본적으로 기기 상태에 따라서 최대 15분까지 지연될 수 있다는 특징이 있습니다. 따라서 만약에 정확한 시각에 실행되어야 하는 등의 정시 실행 시간 개념이 중요하다면, AlarmManager를 사용하는 것을 추천드립니다.

 

+ 여기서 말하는 15분 지연은, 예약된 작업을 의미합니다.

WorkManager 2.7 부터 즉시 실행 가능한 우선순위의 작업이 가능하지만, 이 역시 예약된 시간에 정시로 실행 할 수 있느냐와는 별개입니다.

 

 

AlarmManager

이어서, 이러한 기기 상황에 따른 AlarmManager의 방안에 대해서도 차례로 살펴보겠습니다.

 

set(type, triggerAtMillis, pendingIntent)

기본적인 알람, 정확도가 낮고 시스템 상황에 따라 지연될 수가 있습니다.

 

setExact(type, triggerAtMillis, pendingIntent)

정확한 시간에 한 번 실행된다고 하지만, Doze 모드에서는 무시됩니다..

 

setReapting(type, triggerAtMillis, intervalMillis, pendingIntent)

정기적인 반복, 하지만 역시나 Doze/Idle 상태에서는 작동하지 않습니다..

 

setAndAllowWhileIdle(type, triggerAtMillis, pendingIntent)

Doze 모드/ Idle 상태에서도 실행 가능하지만, 9분에 한 번만 실행할 수 있다는 단점은 있습니다.

 

setAlarmClock(alarmClockInfo, operation)

시스템이 최우선으로 실행을 보장합니다.

+ 경험상 실행된 알람을 관리하는 데에도 굉장히 유용하고 간편합니다.

 

 

이러한 알람 함수들과, 기기 상태에 대한 대응을 표로 정리하겠습니다.

메서드 설명 Doze 모드 App Standby 배터리최적화 예외 효과 Idle 상태
set() 기본 알람, 정밀도 낮음 X X X X
setExact() 정확한 시간 지정 X X X X
setRepeating() 반복 알람 X X X X
setAndAllowWhileIdle() 약간 느슨한 정확도, Idle 대응 O X X O (정확도 낮음)
setExactAndAllowWhileIdle() 정확한 시간 + Idle 대응 O X X O (정확하게)
setAlarmClock() 사용자 인지형 알람 (UI 표시됨) O O O O (최우선)

 

setAlarmClock은 모든 앱을 깨우므로, 배터리를 많이 잡아먹을 수 있습니다. 

또한 예약 시간 1시간 전부터 휴대폰이 유휴 상태로 들어가지 않는다는 특징이 있습니다.

 

시간이 엄격한지, 아니면 딜레이가 좀 있어도 되는지를 서비스에 맞게 고민해보세용

꼭 setAlarmClock()이 매우 좋다 가 아니라, 상황에 맞는 적절한 선택을 해서 

리소스를 잘 사용하길 바랍니당!

 

기기 상태 테스트하기

의도된대로 잘 설계되었는지 테스트를 해보기 위해서

앱 대기모드나 도즈모드로 진입해봐야 하는 경우가 생기는데요, ADB를 통해서 테스트 하는 방법을 소개해드립니다.

제가 사용했던 방식인데, 필요하신 분들은 참고하세요!

 

잠자기 모드 (IDLE)

화면 끄고 진행한다 (순서대로)

 

배터리 연결 해제

adb -s 27dc9135f0217ece shell dumpsys battery unplug

 

idle eanble

adb -s 27dc9135f0217ece shell dumpsys deviceidle enable

 

deep idle 접근

adb -s 27dc9135f0217ece shell dumpsys deviceidle force-idle

 

deep idle 해제

adb -s 27dc9135f0217ece shell dumpsys deviceidle unforce

 

idle disable

adb -s 27dc9135f0217ece shell dumpsys deviceidle disable

 

배터리 연결 초기화

adb -s 27dc9135f0217ece shell dumpsys battery reset

 

대기 모드(Standby)

 

화면 끄고 진행한다 (순서대로)

 

배터리 연결 해제

adb -s 27dc9135f0217ece shell dumpsys battery unplug

 

대기 모드 진입

adb shell am set-inactive <packageName> true

 

현재 모드 확인

adb shell am get-inactive <packageName>

 

대기 모드 해제

adb shell am set-inactive <packageName> false

 

 

도움이 되셨으면 좋겠습니다.

 

반응형