사전 백그라운드 실행 제한
한계

백그라운드 실행 제한

gabury1고친 사람 github-actions[bot]

백그라운드 실행 제한은 화면 밖에 있는 앱이 일하지 못하게 운영체제가 막는 규칙입니다. 앱은 이 규칙을 끌 수 없습니다. 운영체제가 허락한 방식으로 일을 옮길 수만 있습니다. 서버를 주기적으로 부르던 앱이 화면 밖에서 조용해지는 까닭이 이것입니다.

쉽고 빠른 이해

무슨 일을 하나 — 사용자가 보고 있지 않은 앱이 배터리와 메모리를 쓰지 못하게 막습니다. 날씨 앱이 화면 밖에서 1분마다 서버에 물어보려 해도 운영체제가 그 일을 멈춥니다.

왜 이렇게 하나 — 폰 하나에 앱이 수십 개 깔려 있습니다. 저마다 화면 밖에서 깨어나 일하면 사용자가 아무것도 안 해도 배터리가 닳습니다.

어떻게 도나

  1. 앱이 화면에서 내려가면 몇 분 뒤 운영체제가 그 앱의 일을 멈춥니다
  2. 화면이 꺼진 채 폰이 가만히 놓이면 네트워크와 알람도 미룹니다
  3. 꼭 해야 하는 일은 알림을 띄우고 돌거나, 시스템에 맡겨 나중에 돌립니다

무엇이 나빠지나 — 앱이 원하는 때에 일하지 못합니다. 서버 쪽에서는 앱의 요청이 늦게 옵니다. 몰려서 오기도 하고 중간에 끊기기도 합니다.

상세

이 절은 화면 밖의 앱이 무엇을 못 하게 되는지부터 봅니다. 그다음 앱이 그 선을 넘지 못하는 까닭과 우회하는 길을 봅니다. 마지막으로 이 제한이 서버 쪽에 남기는 흔적을 봅니다.

백그라운드 실행 제한은 화면 밖에 있는 앱이 할 수 있는 일을 운영체제가 줄이는 규칙입니다. 음악 앱은 다른 앱으로 넘어가도 계속 소리를 내야 합니다. 반면 사진 앱이 화면 밖에서 사진을 정리하는 일은 사용자가 기다리는 일이 아닙니다. 지금 멈춰도 곤란한 사람이 없습니다. 운영체제는 앞의 것은 허락합니다. 뒤의 것은 멈춥니다.

포그라운드와 백그라운드

앱은 두 처지로 갈립니다. 사용자 눈에 띄는 쪽이 포그라운드입니다. 나머지가 백그라운드입니다. 제한은 백그라운드에만 걸립니다.

화면에 창이 없어도 사용자 눈에 띄는 작업이 있습니다. 포그라운드 서비스는 상단 알림을 띄운 채 도는 작업입니다. 알림이 떠 있으니 사용자는 무엇이 돌고 있는지 압니다. 음악 재생이나 길 안내가 이렇게 돕니다.

안드로이드는 셋 중 하나라도 맞으면 그 앱을 포그라운드로 봅니다. 화면에 보이는 창이 있을 때, 포그라운드 서비스를 돌리고 있을 때, 화면에 떠 있는 다른 앱이 이 앱의 기능을 불러 쓰고 있을 때입니다. 지금 쓰는 메신저 앱이 다른 앱의 사진 편집 기능을 빌려 쓰는 동안에는 그 편집 앱도 포그라운드로 칩니다. 셋 다 아니면 백그라운드입니다.

막는 이유

폰은 배터리로 돕니다. 앱 하나가 화면 밖에서 잠깐 깨어나는 것은 작은 일입니다. 하지만 깔린 앱 수십 개가 저마다 깨어나면 사용자가 폰을 안 만져도 배터리가 닳습니다.

메모리도 같습니다. 화면 밖의 앱이 프로세스를 띄우고 버티면 지금 쓰는 앱이 쓸 메모리가 줄어듭니다. 그래서 운영체제는 화면 밖의 앱을 되도록 적게 돌리는 쪽으로 규칙을 세웁니다.

예전 안드로이드에서는 네트워크 연결이 바뀌었다는 신호를 받겠다고 미리 등록해 둔 앱이 많았습니다. 신호가 오락가락할 때마다 그 앱들이 한꺼번에 깨어났습니다. 이런 일이 쌓여 제한이 생겼습니다.

무엇이 막히나

안드로이드는 8.0부터 화면 밖의 앱에 큰 제한 두 가지를 걸었습니다. 하나는 서비스입니다. 서비스는 화면 없이 오래 도는 작업 단위입니다. 다른 하나는 방송입니다. 방송은 시스템이나 다른 앱이 보내는 신호입니다. 앞 소절의 「네트워크 연결이 바뀌었다」는 신호도 방송입니다.

서비스 제한은 이렇습니다. 앱이 화면에서 내려가면 몇 분 동안은 서비스를 계속 돌릴 수 있습니다. 그 시간이 지나면 운영체제가 그 앱의 서비스를 멈춥니다. 백그라운드에 있는 앱은 새 서비스를 띄우지도 못합니다.

방송 제한은 브로드캐스트 리시버에 걸립니다. 브로드캐스트 리시버는 앱 안에서 방송을 받아 처리하는 부분입니다. 앱은 받고 싶은 방송을 리시버에 미리 등록해 둡니다.

방송 가운데 받을 앱을 정하지 않고 보내는 것이 암시적 방송입니다. 받겠다고 등록한 앱이면 누구나 받습니다. 네트워크 연결이 바뀌었다는 신호가 이런 방송입니다.

리시버를 등록하는 곳은 두 군데입니다. 하나는 매니페스트입니다. 매니페스트는 앱을 설치할 때 운영체제가 읽는 설정 파일입니다. 여기 적어 둔 리시버는 앱이 꺼져 있어도 방송이 오면 운영체제가 앱을 깨워 부릅니다.

다른 하나는 앱이 떠 있는 동안 코드에서 등록하는 것입니다. 8.0의 방송 제한은 매니페스트 쪽을 막았습니다. 매니페스트에 적은 리시버로 암시적 방송을 받는 길이 대부분 닫혔습니다.

코드에서 등록한 리시버는 앱이 떠 있는 동안 암시적 방송도 받습니다. 막힌 것은 꺼져 있는 앱을 방송으로 깨우는 길입니다.

제한은 배터리를 아끼는 정책 둘로 더 넓어집니다. Doze는 화면이 꺼진 채 폰이 한동안 가만히 놓여 있으면 켜지는 절전 상태입니다. 이 상태에서는 앱의 네트워크 접근과 알람이 미뤄집니다. 앱이 시스템에 맡겨 둔 예약 작업도 함께 미뤄집니다. 사용자가 화면을 켜거나 충전기를 꽂으면 이 상태에서 깨어납니다.

잠든 동안에도 운영체제는 가끔 짧은 정비 시간을 엽니다. 그때 미뤄 둔 네트워크 요청과 작업을 몰아서 처리합니다. 잠든 시간이 길어질수록 정비 시간 사이의 간격도 벌어집니다.

stateDiagram-v2
    state "쓰는 중" as Use
    state "잠듦 · 네트워크와 알람이 미뤄진다" as Sleep
    state "정비 시간 · 밀린 일을 몰아서 한다" as Maint
    [*] --> Use
    Use --> Sleep: 화면이 꺼지고 한동안 가만히 놓임
    Sleep --> Maint: 시간이 흐름
    Maint --> Sleep: 정비 시간이 끝남
    Sleep --> Use: 화면을 켬 · 충전기를 꽂음

앱 스탠바이는 앱 단위로 걸립니다. 사용자가 한동안 열지 않은 앱은 네트워크와 예약 작업을 덜 자주 받습니다. 폰이 깨어 있어도 이 앱만 느려집니다.

iOS는 더 일찍 멈춥니다. 앱이 화면에서 내려가면 잠시 뒤 코드 실행이 멈춘 상태가 됩니다. 계속 돌 수 있는 앱은 음악 재생, 위치 추적, 인터넷 전화처럼 용도를 미리 밝힌 앱으로 한정됩니다. 그 밖의 앱은 하던 일을 마치도록 짧은 추가 시간을 요청할 수 있습니다.

플랫폼 막히는 일 남는 길
안드로이드 화면 밖에서 서비스 띄우기 포그라운드 서비스 · 예약 작업
안드로이드 매니페스트 리시버로 암시적 방송 받기 앱이 떠 있는 동안만 리시버 등록 · 예약 작업
안드로이드 Doze 중의 네트워크 · 알람 정비 시간 · 우선순위 높은 푸시
iOS 화면에서 내려간 뒤의 코드 실행 미리 밝힌 용도 · 짧은 추가 시간 요청 · 예약 작업

표의 「남는 길」은 제한을 푸는 길이 아닙니다. 운영체제가 허락한 틀 안으로 일을 옮기는 길입니다.

앱이 넘을 수 없는 까닭

이 선은 플랫폼이 정한 규칙입니다. 앱의 코드가 아니라 운영체제가 앱을 멈추고 미룹니다. 그래서 앱 쪽에서 아무리 손을 써도 끌 수 없습니다.

선을 옮길 수 있는 것은 플랫폼과 사용자뿐입니다. 앱은 어느 안드로이드 버전에 맞춰 만들었는지를 스스로 밝혀 둡니다. 8.0 이상에 맞췄다고 밝힌 앱에는 이 제한이 기본으로 걸립니다. 그보다 옛 버전에 맞춘 앱에도 사용자가 설정에서 이 제한 대부분을 켤 수 있습니다.

반대 방향도 사용자 몫입니다. 배터리 최적화는 Doze와 앱 스탠바이처럼 배터리를 아끼려고 앱의 일을 미루는 정책을 묶어 부르는 이름입니다. 사용자는 설정에서 특정 앱을 이 대상에서 빼 줄 수 있습니다. 빠진 앱은 Doze와 앱 스탠바이의 제한을 덜 받습니다. 앱은 그 설정 화면을 열어 달라고 부탁만 할 수 있습니다.

우회는 일을 옮기는 것

우회 길은 셋입니다. 어느 길로 갈지는 일의 성격이 정합니다. 사용자가 알아차리는 일인지, 서버가 지금 바로 알려야 하는 일인지를 차례로 묻습니다.

flowchart TD
    A["앱이 화면 밖에서 일하려 한다"] --> B{"사용자가 알아차리는 일인가"}
    B -->|그렇다| C["포그라운드 서비스 · 알림을 띄우고 돈다"]
    B -->|아니다| D{"서버가 지금 바로 알려야 하는 일인가"}
    D -->|아니다| E["예약 작업 · 시스템이 때를 고른다"]
    D -->|그렇다| F["푸시로 깨워 잠깐 돈다"]

포그라운드 서비스는 알림을 띄우고 도는 길입니다. 알림을 띄우는 순간 그 앱은 포그라운드가 되어 제한 밖으로 나옵니다. 안드로이드에서는 포그라운드 서비스를 시작한 앱이 5초 안에 알림을 띄워야 합니다. 띄우지 않으면 시스템이 서비스를 멈춥니다. 그리고 앱이 응답하지 않는다고 판정합니다.

예약 작업은 할 일과 조건만 시스템에 맡기는 길입니다. 「충전 중이고 와이파이에 붙었을 때」 같은 조건입니다. 언제 돌릴지는 시스템이 고릅니다. 안드로이드의 JobScheduler와 WorkManager가 이 길입니다.

푸시는 서버가 앱을 깨우는 길입니다. 서버가 푸시 알림 서비스를 거쳐 앱에 메시지를 보냅니다. 앱이 스스로 서버를 주기적으로 묻는 폴링 대신 쓰는 길입니다.

안드로이드에서 이 일을 맡는 것이 FCM(Firebase Cloud Messaging)입니다. FCM은 서버가 넘긴 메시지를 폰의 앱까지 전해 주는 구글의 서비스입니다. 서버는 메시지를 보낼 때 우선순위를 붙입니다. 우선순위를 높게 붙인 메시지를 받은 앱은 몇 분 동안 제한 없이 서비스를 띄울 수 있습니다.

세 길 모두 선을 넘지 않습니다. 포그라운드 서비스는 사용자에게 보이게 만들어서 허락을 받습니다. 예약 작업은 시스템에 때를 맡겨서 받습니다. 푸시는 서버가 우선순위 높은 메시지로 깨워서 받습니다.

서버에서 보이는 흔적

백엔드 개발자가 이 제한을 만나는 곳은 서버 로그입니다. 앱 코드가 아니라 앱이 보내는 요청의 모양이 바뀝니다. 흔적은 셋입니다.

앱이 정해 둔 주기로 서버를 부르지 못합니다. 화면 밖에서 1분마다 묻는 폴링은 멈춥니다. 서버가 새 소식을 앱에 알려야 한다면 서버 쪽에서 푸시를 보내야 합니다.

요청이 늦게 올 수도 있습니다. Doze 중에는 앱의 요청이 정비 시간까지 미뤄집니다. 서버에서 보면 한동안 조용하다가 한꺼번에 들어오는 모양이 됩니다.

요청이 중간에 끊길 수도 있습니다. 앱이 큰 파일을 올리다 화면에서 내려가면 운영체제가 그 일을 멈출 수 있습니다. 앱은 나중에 같은 요청을 다시 보냅니다.

그래서 서버는 같은 요청이 두 번 와도 한 번만 처리되게 만들어 둡니다. 이 성질이 멱등성입니다.

관련 항목

이 제한을 이루는 안드로이드 절전 정책

Doze · 앱 스탠바이 · 앱 스탠바이 버킷 · 배터리 최적화 · 암시적 방송

제한 안에서 일을 넘겨받는 실행 수단

포그라운드 서비스 · WorkManager · JobScheduler · 알람 매니저 · 작업 예약 · BGTaskScheduler

서버가 앱을 깨우는 통로

푸시 알림 · FCM · APNs · 무음 푸시 · 폴링

이 제한이 걸리는 앱 구성 요소

서비스 · 브로드캐스트 리시버 · 액티비티 · 매니페스트 · 프로세스 · 앱 생명주기

늦게 오고 끊기는 요청을 받아 내는 서버 쪽 대비

멱등성 · 재시도 · 지수 백오프 · 재개 가능한 업로드

이 제한이 속하는 상위 분류

모바일 개발 · Android · iOS · 운영체제 · 전력 관리 · 알림

다른 이름: background execution limits · background execution limit · 백그라운드 제한