안드로이드 절전 정책으로 끊기던 새벽 알림 수집 해결
목차
24시간 돌려야 하는 수집기, 새벽마다 멈췄음
알림 수집 모듈을 백그라운드로 24시간 띄워놓는 구조였는데, 새벽 3~5시 사이에 수집이 끊기는 현상이 반복됐음. 처음엔 네트워크 이슈인 줄 알았는데 로그를 까보니 프로세스 자체가 잠들어 있었음. Doze 모드와 App Standby가 만든 합작품이었음.
Doze가 뭘 죽이는지부터 정리
배터리 최적화 정책이 깊은 잠 상태에서 다음을 차단함.
| 항목 | Doze 영향 | 영향도 |
|---|---|---|
| 네트워크 접근 | 차단 | 치명적 |
| Wake CPU | 차단 | 치명적 |
| 알람 발화 | 지연·합산 | 큼 |
| 일반 Job | 보류 | 큼 |
| GPS/센서 | 일부 차단 | 중간 |
수집기는 외부 이벤트에 반응해야 하는데 CPU가 깊게 잠들면 이벤트 콜백 자체가 큐잉되다가 한참 뒤에야 처리됨. 새벽 시간대 단말 미사용 + 충전 미연결이 겹치면 Doze 단계가 깊어져서 수집 윈도우를 통째로 놓침.
PARTIAL_WAKE_LOCK으로 최소 가동 보장
전체 화면 잠금을 푸는 건 과해서 PARTIAL만 잡았음. CPU만 깨워두고 화면/키보드는 그대로 둠.
val wl = pm.newWakeLock(
PowerManager.PARTIAL_WAKE_LOCK,
"collector::ingest"
)
wl.setReferenceCounted(false)
wl.acquire(10 * 60 * 1000L) // 안전 타임아웃
try {
runIngestCycle()
} finally {
if (wl.isHeld) wl.release()
}
핵심 원칙 몇 가지를 못 박았음.
- 반드시 timeout 인자를 줘서 영원히 잡히지 않게 함. 예전에 release 누락으로 배터리 8% 더 빠진 적 있어서 트라우마임.
- try/finally 강제. 예외 던지고 wakelock 살아있으면 그 단말은 그날 하루 끝남.
- acquire 범위는 최소 단위. 전체 서비스 수명이 아니라 ingest 1사이클만 감쌌음.
- 태그에 모듈명::용도 형식 박아둠. dumpsys에서 누가 잡고 있는지 한눈에 보여야 새벽 디버깅이 가능함.
그래도 부족해서 보강한 것
WakeLock만으로 안 풀리는 케이스가 남았음. Doze가 깊어지면 알람 자체가 안 떠서 acquire를 호출할 트리거가 사라짐. 그래서 추가로 처리.
- 정확 알람으로 진입점 보장. 사용자에게 권한 안내 다이얼로그 한 번 띄워서 허용 받음.
- 전경 서비스 노티 항상 노출. "수집 중" 표시가 사용자 입장에선 거슬리지만 OS 입장에선 살려두는 명분이 됨.
- 제조사별 화이트리스트 가이드 문서화. 일부 제조사는 표준 API 위에 자체 절전 정책을 또 얹어놔서 OS 표준만 믿으면 안 됨.
결과
배포 후 1주일 모니터링했을 때 새벽 시간대 수집 누락이 사실상 0으로 떨어짐. 배터리 영향은 일평균 +1.5% 수준이라 받아들일 만했음. 무엇보다 "왜 어제 새벽 데이터만 비어있냐"는 문의가 사라진 게 제일 큼.
다음
댓글 0
첫 댓글 달아줘.