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

[당신이 잠든 사이에] 포그라운드 서비스와 백그라운드 서비스의 변천사 (Service, IntentService, JobIntentService, WorkManager, AlarmManager)

by Hevton 2025. 3. 31.
반응형

 

'당신이 잠든 사이에' 앱을 2017년부터 개발하여 유지하면서, 'Service' 에 대한 정책적인 변화를 겪어왔습니다.

이번 글에서는 'Service' 의 개념과 종류, 그리고 정책이 변화되면서 무엇이 없어졌고 생겼는지에 대한 변천사도 간단히 정리해보려 합니다.

 

 

글을 읽기 전에,

AlarmManager의 다양한 함수들(set, setExact, setExactAndWhileIdle, setAlarmClock)와

Doze/App Standby/Idle/배터리 최적화 제외 등의 개념을 작성해 놓은 글이 있어서, 먼저 참고하시면 좋을 것 같습니다

https://hevton.tistory.com/899

 

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

Doze 모드, App Standby, 배터리 최적화, Idle 상태, 백그라운드 실행 제한 등정책들이 날이 갈수록 새로 생겨나면서, 저희 같은 서비스를 운영하는 사람들에게는 이만 저만 어려운 점이 많습니다ㅜㅜ

hevton.tistory.com


 

 

 

Service는 4대 컴포넌트 중 하나입니다.

앱이 종료되었더라도 실행될 수 있다는 점에서 강력한 의미를 갖고 있습니다.

 

이러한 서비스에는 '포그라운드 서비스', '백그라운드 서비스'로 크게 2가지 종류가 있습니다.

사실 옛날에도 개념이 2가지로 분류되어 있었지만, 구분이 엄격하진 않았습니다.

하지만 Android 버전이 점점 올라가면서 두 가지 서비스가 엄격하게 구분되고 분리되기 시작했습니다.

 

포그라운드 서비스와 백그라운드 서비스에 대한 실험을 해봤었는데, 관심있으신 분들은 제 포스팅을 한 번 보셔도 재밌을 것 같습니다!

 

 

1. 포그라운드 서비스

상태창에 Notification이 동반된 서비스. 사용자에게 명시적인 서비스라는 의미를 갖고 있습니다.

사용자에게 명시적인 서비스답게, 실행의 우선순위가 백그라운드 서비스보다 높으며, 시스템에 의해 강제로 종료될 가능성이 낮습니다.

 

API 26(Oreo) 이전까지는 포그라운드 서비스의 개념이 그다지 중요한 편은 아니었는데요

이후부터 '백그라운드 실행 제한' 정책이 도입되면서, 백그라운드에서는 startService를 통해 백그라운드 서비스를 실행할 수 없게 됩니다.

 

저 같은 경우의 예로, 서비스를 실행하던 도중에 휴대폰의 전원이 종료된다면

다시 휴대폰을 켰을 때 해당 작업을 계속해서 진행하기 위해서 BroadcastReceiver의 BOOT_COMPLETED 를 수신받았었는데요

이 BR(BroadcastReceiver) 내에서 startService를 통해서 서비스를 다시 재실행시킬 경우에 IllegalStateException 예외가 발생했습니다.

java.lang.IllegalStateException: Not allowed to start service Intent { ... }: app is in background uid ...

 

백그라운드 서비스가 무분별하게 실행되면 배터리 수명, 성능, 사용자 경험이 저하될 것을 생각하여 정책이 강화되었던 것 같습니다.

그래서 API 26(Oreo) 부터는, 포그라운드 서비스만 백그라운드에서 시작 가능하도록 정책이 바뀌었습니다.

 

 

2. 백그라운드 서비스

백그라운드 서비스는 Notification 없이 백그라운드에서 실행되는 서비스를 말합니다.

포그라운드 서비스와는 달리 눈에 보이지 않으므로, 시스템에 의한 우선순위도 낮습니다.

따라서 포그라운드 서비스 > 백그라운드 서비스의 우선순위를 가지며, 리소스 상황에 따라 시스템에 의해 강제 종료될 가능성도 높습니다.

저도 처음엔 우선순위에 대해 모르고 어리석게 무대뽀로 들이받아서, 이런 경험을 찐~하게 해봤네요

 

백그라운드 서비스를 실행하는 방법에는 그동안 여러가지가 있었는데요, deprecated 된 정보들까지 함께 남겨보겠습니다.

 

IntentService (deprecated)

Android 4대 컴포넌트는 모두 메인 스레드에서 동작합니다. 그렇기 때문에 Service 또한 메인 스레드에서 동작합니다.

따라서 Service가 백그라운드에서 오랜 시간 동안 동작하게 되면 ANR이 발생할 수 있게 되는데요

이 문제를 방지하고자 Service를 구현할 때 서브 스레드를 개발자가 별도로 만들어줘야 합니다. 이러한 귀찮은 과정을 줄여주기 위해

IntentService가 처음 등장했습니다. 하지만 한번에 하나만 실행할 수 있으며, 생명주기를 인식하기 어렵고, 시스템에 의해 작업이 누락될 수 있기 때문에 deprecated 되었습니다.

 

JobIntentService (deprecated)

JobIntentService는 Android 8.0 이하에서 JobScheduler라는 새로운 개념을 활용할 수 있다는 장점이 있었습니다.

하지만 API 26(Oreo) 이하에서는 startService 기반이기 때문에, 위에서 언급했던 IllegalStateException이 발생할 수 있는 취약점이 있습니다. 또한 타임제한이 10분 이하라는 점에서 확정성이 낮아 deprecated 되었습니다.

 

 

WorkManager (백그라운드 서비스 & 포그라운드 서비스 둘 다 활용 가능)

현재 백그라운드 서비스를 구현하는 방법 중에서 가장 권장되는 방법이며, 동시에 setForegroundAsync를 통해 포그라운드 서비스로 스위칭도 가능한 방법입니다.

WorkManager는 시스템에 의해 앱이 강제종료되거나, 심지어 기기가 재부팅되어도 보장된 방식으로 알아서 재실행시켜준다는 이점이 있습니다. 또한 WorkManager는 새로운 기술이라기 보다는, 내부적으로 OS 버전에 따라 적절한 백엔드 (JobScheduler 등) 을 자동으로 선택해서 처리해준다는 이점이 있습니다. 그리고 이전의 방법들과는 달리 LiveData 또는 Flow를 사용해 작업 상태를 관찰 가능하다는 장점이 있어 MVVM 아키텍쳐를 고려하고 있다면 접목하기에 좋다고 생각됩니다.

 

: WorkManager의 내부 동작

API 23 이상 JobScheduler 사용
API 14~22 AlarmManager + BroadcastReceiver + Service 조합

 

하지만 JobScheduler의 특성 상, 기기의 상태에 따라서 작업이 최대 15분까지 딜레이 될 수 있다는 점이 있기에 만약에 정시에 작업이 필요한 경우에는 별도로 AlarmManager를 사용하는 것이 필요합니다.

 

WorkManager 2.7 부터 지금 즉시 실행 가능한 우선순위의 작업이 가능합니다.

하지만 Doze/Idle 등의 상태에 따라 예약된 작업이 정시에 실행되지 않고 딜레이 되는 것은 동일하다고 합니다.

 

 

포그라운드 서비스와 백그라운드 서비스 실행 방법

각 서비스를 언제 실행할 수 있을지를 다음과 같이 정리해보겠습니다.

 

 

앱이 포그라운드 상태일 때

- 포그라운드 서비스, 백그라운드 서비스 둘 다 실행 가능

- 이 때, startService나 startForegroundService나 상관 없이 호출 가능

- 단 포그라운드 서비스를 실행하고자 할 때는, 위 둘 중 하나의 함수 실행 후 5초 안에 startForeground를 호출하지 않으면 예외가 발생합니다

Context.startForegroundService() did not then call Service.startForeground(): ServiceRecord{...}

 

앱이 백그라운드 상태일 때

- 포그라운드 서비스만 실행 가능 (API 26 이후 백그라운드 실행 제한)

- startForegroundService를 호출한 뒤에 5초 안에 startForeground를 호출해서 포그라운드 서비스로 승격시켜야함

 

 

 


 

 

최근에 지인으로부터 두 가지 질문을 받은 적이 있습니다.

"Coroutine 으로 Service를 대체할 수 있는거 아니야?"

"WorkManager를 쓰는 거랑 AlarmManager를 쓰는 거랑 구분을 짓고 있어?"

 

저는 지금 현업에서 안드로이드를 하고 있지 못해서... 따로 집에서 공부만 하는 상황이었는데, 옛날 기억은 많이 나질 않더군요..

이 질문을 듣고 '당신이 잠든 사이에'를 개발할 때를 생각하면서, 정리해보게 되었습니다.

 

우선 코루틴과 서비스의 차이는, 앱이 명시적으로 종료되었을 때에도 실행이 가능하냐에 대한 극명한 차이가 있습니다.

코루틴은 여러가지 scope가 있지만, 결국에 앱이 종료되었을 때에는 코루틴 스코프도 함께 종료됩니다.

이에 반해 Service는 4대 컴포넌트 중 하나로, 그 자체로 독자적인 앱의 실행의 의미를 갖습니다.

 

언제 무엇을 활용하면 좋을지에 대해 아래에 글로 정리해보겠습니다.

틀린 부분이 있다면 지적 부탁드립니다.

 

1. 무조건 즉시 실행 & 사용자에게 알림을 보여야겠다

ForegroundService를 활용하면 됩니다. startForegroundService() -> 5초 안에 startForeground를 호출하지 않으면 IllegalStateException이 발생합니다. 이는 앱이 포그라운드 상황이던, 백그라운드 상황이던 상관 없이 포그라운드 서비스를 실행할 수 있습니다.

 

단, 앱이 주의할 점은 startService()로 서비스를 호출하지 않길 권장드립니다.

경험상 앱이 포그라운드 상태일 때 startService -> startForeground 를 진행하는 것은 문제가 없지만

API 26부터는 앱이 백그라운드 일 때 아예 startService 자체에 대한 호출이 Exception을 유발하기 때문에

포그라운드 서비스를 실행하겠다는 startForegroundService()를 명시적으로 사용하는 것이 좋습니다.

 

 

2. 앱이 살아있고, 백그라운드 작업을 해야겠다

코루틴을 활용하면 됩니다. 네트워크 같이 대기 작업이 긴 IO 작업에 대해서는 Dispatchers.IO를 통해 코루틴을 실행하면 좋고

CPU 연산이 많은 작업에 대해서는 Dispatchers.Default를 통해 코루틴을 실행하면 설계 목적에 맞게 코루틴을 활용할 수 있습니다.

 

 

3. 앱이 꺼져도 백그라운드에서 작업되어야겠다

1. IntentService (Deprecated)

2. JobIntentService (Deprecated)

3. WorkManger

 

WorManager를 추천드립니다. WorkManager는 내부적으로 적절한 방법을 취하면서, 입맛에 따라 setForegroundAsync 를 통해 포그라운드 서비스로 승격까지 할 수 있습니다. 보통은 내부적으로 JobScheduler를 사용하고 있는데,

WorkManager 2.7부터는 작업을 즉시 실행할 수 있지만, 예약된 작업이 있을 때 Idle/Doze 모드에서는 최대 15분까지 딜레이 될 수 있는 가능성이 있습니다. 만약 정확한 시간에 작업이 필요할 경우에는 AlarmManager 를 활용하시는 것을 권장드립니다.

 

 

4. 정확한 시간에 작업이 실행되어야 한다.

AlarmManager & BroadcastReceiver 를 활용하면 됩니다. 또한 백그라운드 실행 정책 제한들이 다양하게 생기면서 어려움이 생길 수 있는데요,

Doze 모드, App Standby, Idle상태에 대한 제약을 모두 우회하기 위해서는 setExactAndAllowWhileIdle()을 사용할 수 있지만 9분에 한 번 사용이 최대라는 제약이 있습니다. 따라서 배터리 소모가 있더라도 꼭 필요하다면 setAlarmClock()을 실행하며, 동시에 배터리 최적화 예외를 받는 것을 권장드립니다.

 

AlarmManager와 다양한 기기 상태에 대한 글은 아래 제가 작성해 놓은 포스팅을 참고하세요!

https://hevton.tistory.com/899

 

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

Doze 모드, App Standby, 배터리 최적화, Idle 상태, 백그라운드 실행 제한 등정책들이 날이 갈수록 새로 생겨나면서, 저희 같은 서비스를 운영하는 사람들에게는 이만 저만 어려운 점이 많습니다ㅜㅜ

hevton.tistory.com

 

 

틀린 내용 의견 부탁드립니다!

 

 

참고 문헌

- Android 백그라운드 실행 제한

- Android 백그라운드 작업 개요

- Android WorkManager

- 참고 블로그

 

반응형