[번역] [Android O Preview] Background Execution Limits

Background Execution Limits







언제든, 앱이 백그라운드에서 실행하려고 하면, 앱은 램과 같은 디바이스의 제한된 리소스를 소비하게 된다.
이로 인해 사용자가 게임이나 비디오 감상처럼 리소스 집약적인 앱을 사용할 경우 사용자 경험이 손상될 수 있다.
 Android O에서는 사용자 경험을 개선시키기 위해 백그라운드에서 실행되는 동안 앱이 할 수 있는 것들에 제한을 두고있다.
 이 문서는 OS의 변화와, 이러한 새로운 제한환경안에서 당신의 앱이 잘 구동될 수 있도록 어떻게 업데이트를 해야하는지를 기술하고 있다.

개요


많은 안드로이드 앱들과 서비스들은 동시에 실행될 수 있다. 예를 들어, 사용자가 하나의 윈도우에서 게임을 하고 있고 다른 윈도우에서는 웹브라우징을 하며, 음악감상을 위해 세번째 앱을 쓸 수 있다.

 한번에 더 많은 앱을 실행할 수록, 시스템에는 더 많은 부하가 걸린다.
 만약 추가적인 앱/서비스가 백그라운드에서 실행되고 있다면,  시스템에 추가적인 부하가 발생해서 사용자 환경이 좋지 않을 수 있다. 예를 들어, 뮤직앱이 갑자기 종료된다거나..
이러한 경우를 낮추기 위해, Android O에서는 사용자가 직접 상호작용하지 않는 동안 앱들이 무엇을 할 수 있는지에 대한 제한을 두었다. 만약 앱의 타겟이 Android O인 경우, 아래 두가지 방법으로 제한된다.
  • Background Service 제한 : 앱이 Idle 상태인 동안, 백그라운스 서비스 사용에 제한이 있다. 이것은 사용자들에게 좀 더 잘 보이는 Foreground service에는 적용되지 않는다.
  • Broadcast 제한 : 앱은 예외를 제외하고, implicit broadcasts를 등록하기 위해 manifest를 사용할 수 없다. 그것들은 런타임에 브로드캐스트를 등록할 수 있고, 메니페스트를 통해서는 자신의 앱을 대상으로 Explicit broadcast를 등록할 수 있다. 
대부분의 경우, 앱은 JobScheduler job을 사용해서 이러한 제한사항을 해결 할 수 있다. 이 방법을 사용하면 앱이 실제로 실행되고 있지 않을때 작업을 수행할 수 있고, 그렇다더라도 사용자 경험에 영향을 미치지 않는 방식으로 이러한 작업을 예약할 수 있는 여유가 생긴다.

Background Service Limitations


백그라운드에서 실행중인 서비스는 디바이스의 리소스를 소비할 수 있으므로, 잠재적으로 사용자 경험을 나쁘게 만들 수 있다.  이 문제를 완화하기 위해, 시스템은 target이 Android O인 앱들에 몇가지 서비스제한을 적용한다.
Note: 이 제한은 Android O를 타겟으로하는 앱들에만 적용된다. 앱의 타겟 API가 25이하인 경우에는 영향을 미치지 않는다.
시스템은 foreground와 background앱을 구분한다.(서비스 제한을 위한 background의 정의는, 메모리 관리에서 사용되는 정의와 다르다. 앱은 백그라운드 상태일때는 메모리 관리와 관련될 수 있지만, 포그라운드 상태에서는 서비스를 시작하는 기능과 관련된다.) 다음중 하나라도 해당된다면, 포그라운드 앱으로 간주된다.
  • Activity가 started/paused이든, 하나의 보여지는 Activity를 갖고있다. 
  • 하나의 포그라운드 서비스를 가지고 있다.
  • 또 다른 Foreground 앱이 이 앱의 서비스중 하나에 binding되었거나, 이 앱의 Content Provider중 하나를 사용하여 연결되었다. 예를 들어 앱이 아래것들 중 하나에 바인드 된 경우는 포그라운드 이다:
    • IME
    • Wallpaper service
    • Notification listener
    • Voice or text service
만약 위의 조건들 중 어떤것도 해당되지 않는다면, 그 앱은 백그라운드로 간주된다.
하나의 앱이 포그라운드로 있는 동안은, foreground 혹은 background service를 자유롭게 생성하고 실행할 수 있다. 앱이 백그라운드로 들어가게 되면 몇분간은 여전히 서비스를 생성하고 사용할 수 있는 윈도우가 주어진다. 해당 윈도우가 끝나게 되면, 앱은 idle 상태로 간주된다. 이때, 시스템은 마치 서비스의 Service.stopSelf()를 호출한 것 처럼, 앱의 백그라운드 서비스를 중지한다.
특정 상황에서, 백그라운드 앱은 수분간 임시 whitelist에 등록된다. 앱이 whitelist에 있는 동안, 제한없이 서비스를 시작할 수 있으며, 백그라운드 서비스가 실행되도록 허용된다. 앱이 사용자가 볼 수 있는 작업을 처리할때 whitelist에 등록된다. 예를 들면 :
  • 높은 우선순위의 Firebase Cloud Messaging (FCM) 메시지를 처리할때
  • SMS/MMS 메시지와 같은 broadcast를 수신할때.
  • Notification에서 PendingIntent를 실행할 때
대부분의 경우, 앱의 백그라운드 서비스는 JobScheduler job으로 교체될 수 있다.예를들어, CoolPhotoApp은 포그라운드에서 실행되지 않더라도, 친구가 공유한 사진을 수신했는지 여부를 확인해야 한다. 이전에 이 앱은 앱의 클라우드 저장소를 체크하는 백그라운드 서비스를 사용했다. Android O로 migrate 하기위해, 개발자는 백그라운드 서비스를 scheduled job으로 변경해서 주기적으로 실행해 서버에 쿼리를 날리고 종료하도록 했다. Android O 이전에는 포그라운드 서비스를 만드는 일반적인 방법은, 백그라운드 서비스를 만든 후 서비스를 포그라운드로 승격하는 것이었다. Android O를 사용하면, 앱이 현재 백그라운드 서비스를 만들 수 없는 경우에는 이 방법이 실패한다.
이러한 이유로, Android O는 새로운 Method인 NotificationManager.startServiceInForeground()를 소개한다. 이 메소드를 호출하면, startService() 를 호출한것과 동일하게 서비스를 백그라운드에서 생성한 다음 즉시 서비스의 startForeground() 메소드를 호출하여 포그라운드로 승격시킨다. 이 서비스는 백그라운드가 아니기 때문에, 백그라운드 서비스에 대한 제한이 적용되지 않는다. 

Broadcast Limitations


만약 앱이 broadcast receiver를 등록한다면, 앱은 broadcast가 보내질 때 마다 리소스를 소모하게 된다. 만약 앱이 system event에 관련된 너무 많은 broadcast receiver를 등록한다면 문제의 원인이 될 수 있다. 하나의 시스템 이벤트 broadcast로 인해 모든 앱이 빠르게 연속적으로 리소스를 소비하게 되어 사용자 환경이 나빠질 수 있다.
이 문제를 완화시키기 위해, Android 7.0에서는 Background Optimization에 기술된것 처럼 Broadcast에 제한을 두었다.
Android O에서는 이 제한들을 좀 더 엄격하게 만들었다.
Note: 이 제한들은 Android O target일때 적용된다. 앱의 target API가 25 이하인 경우는 영향받지 않는다. 
  • Target이 Android O인 앱들은 더이상 implicit broadcast를 manifest에서 등록할 수 없다. Implicit broadcast는 앱을 구체적으로 타겟팅하지 않는 Broadcast이다.
    예를 들어, ACTION_PACKAGE_REPLACED는 implicit broadcast이다. 등록된 모든 리스너를 통해, 장치의 일부 패키지가 교체되었음을 알수 있게 해준다.
    그러나, ACTION_MY_PACKAGE_REPLACED는 패키지가 교체된 앱에만 전송되기 때문에 Implicit broadcast가 아니며,  얼마나 많은 다른 앱들이 해당 Broadcast를 위해 리스너를 등록했던 것과 관계 없이 전송된다.
  • 앱은 Explicit broadcast를 manifest에 계속 등록할 수 있다. 
  • 앱은 Implicit/Explicit Broadcast Receiver를 등록하기 위해 Context.registerReceiver()를 런타임에 사용할 수 있다. 
대부분의 경우에서, Implicit broadcast를 위해 등록했었던 앱들은 비슷한 기능을 JobScheduler job을 이용해서 작업을 수행할 수 있다. 예를들어, 소셜 사진앱은 수시로 데이터를 정리해야 할 수 있으며, 이 작업을 하기위해 단말이 충전상태일 때를 선호한다. 이전에, 앱은 manifest에서 ACTION_POWER_CONNECTED를 위한 receiver를 등록했었다. 앱이 broadcast를 받으면, 앱은 정리가 필요한지 확인한다.
Android O로 migrate 하기위해, 앱은 manifest에서 Receiver를 제거한다. 대신에 앱은 단말이 idle 상태에서 충전상태가 될때 수행하는 정리 작업을 예약한다.
Note: 몇몇 Implicit broadcast는 아직도 이 제한에 해당되지 않는다. 앱은 Target API Level에 관계 없이 여전히 이 Broadcast들을 manifest에서 등록할 수 있다. 이 broadcast들의 목록은 Implicit Broadcast Exceptions에서 확인할 수 있다.

Migration Guide


이 변경들은 Target API Level 25 이하에서는 영향받지 않는다.
만약 앱의 Target이 Android O라면, 앱을 새로운 제한사항에 맞춰서 업데이트 할 필요가 있다.
앱이 서비스를 사용하는 방식을 확인하라.
만약 앱이 idle 상태일 때 백그라운드에서 서비스를 실행시킨다면, 수정할 필요가 있다. 가능한 해결방법은 아래와 같다.
  • 만약 너의 앱이 백그라운드 일 동안, foreground Service를 생성해야 한다면, 백그라운드 서비스를 만들어서 foreground로 승격시키려 하지 말고, 새로운 Method인 NotificationManager.startServiceInForeground()를 사용해라. 
  • If the service is noticeable by the user, make it a foreground service.
    만약 서비스를 사용자에게 알려지게 하려면, foreground service로 만들어라. 예를들어, 서비스가 오디오를 재생한다면, 항상 foreground service여야 한다. 서비스를 만들기 위해 startService() 대신  NotificationManager.startServiceInForeground()를 사용해라.
  • 서비스의 기능을 scheduled job을 이용해 복제항 방법을 찾아라. 만약 서비스가 사용자에게 즉시 눈의 띄일만한 것을 하지 않는다면, 일반적으로 scheduled job을 이용해 대체될 수 있다.
  • 백그라운드에서 폴링하는 대신 네트워크 이벤트가 발생할때 FCM을 이용해 선택적으로 앱을 깨워라
  • 앱이 자연스럽게 foreground에 올때까지 백그라운드 작업을 미뤄라.
Broadcast Receiver를 manifest에 정의하고 있는지 확인하라. 만약 implicit broadcast의 Receiver를 manifest에 선언했다면, 이것을 교체해야 한다. 가능한 방법은 아래와 같다. 
  • Receiver를 manifest에서 선언하지 말고, Context.registerReceiver()를 이용해 runtime에 생성해라. 
  • implicit broadcast를 트리거한 Condition을 check하기 위해 scheduled job을 이용하라.

댓글

이 블로그의 인기 게시물

[Android] DataBinding의 동작방식 - 4. include Tag 혹은 ViewStub 사용시의 Binding

[Android] Retrofit2, OkHttpClient Method 정리

[Android] Layout별 성능 비교[Measure 호출횟수 비교] (LinearLayout vs RelativeLayout vs ConstraintLayout)