노블의 개발이야기

[Android] Android O - Background Execution Limits 본문

Android

[Android] Android O - Background Execution Limits

더플러스 2017. 7. 13. 17:39

Android O에서는 사용자 경험을 개선시키기 위해 백그라운드에서 실행되는 동안 앱이 할 수 있는 것들에 제한을 두고 있다.

한번에 많은 앱을 실행할 수록 시스템에는 많은 부하가 걸린다.
이런 경우를 낮추기 위해, Android O에서는 사용자가 직접 상호작용하지 않는 동안 앱들이 무엇을 할 수 있는지에 대한 제한을 두었다.

만약, 앱의 타겟이 Android O인 경우 아래 두가지 방법으로 제한된다.

  • Background Service 제한

    • 앱이 Idle 상태인 동안, 백그라운드 서비스 사용에 제한이 있다.
    • 사용자에게 좀 더 잘 보이는 Foreground service에는 적용되지 않는다.
  • Broadcast 제한

    • 앱은 예외를 제외하고, Implicit broadcasts를 등록하기 위해 manifest를 사용할 수 없다.
    • 런타임에 브로드캐스트를 등록할 수 있다.
    • 메니페스트를 통해서는 자신의 앱을 대상으로 Explicit broadcast를 등록할 수 있다.

대부분의 경우, 앱은 JobScheduler job을 사용해서 이러한 제한사항을 해결 할 수 있다.
이 방법을 사용하면 앱이 실제로 실행되고 있지 않을 때 작업을 수행할 수 있고, 사용자 경험에 미치지 않는 방식으로 이러한 작업을 예약할 수 있는 여유가 생긴다.


Background Service Limitations


백그라운드에서 실행중인 서비스는 디바이스의 리소스를 많이 소비한다.
이 문제를 완화하기 위해 target이 Android O인 앱들에 몇가지 서비스 제한을 적용한다.

Android O 타겟으로 하는 앱들에만 적용됩니다.

Foreground / Background

다음 중 하나라도 해당된다면 포그라운드 앱으로 간주된다.

  • Activity가 Started/Paused 이든 하나의 보여지는 Activity를 갖고 있다.

  • 하나의 포그라운드 서비스를 가지고 있다.

  • 또 다른 Foreground 앱이 이 앱의 서비스중 하나에 binding 되어있거나, 이 앱의 Content Provider 중 하나를 사용하여 연결 되어있다. 예를 들어 아래 중 하나에 바인드 된 경우 포그라운드 이다.

    • IME
    • Wallpaper service
    • Notification listener
    • Voice or text service

위 조건들 중 어떤 것도 해당되지 않는다면, 그 앱은 백그라운드로 간주된다.

Bacground Service 중지

하나의 앱이 포그라운드로 있는 동안은 포그라운드 혹은 백그라운드 서비스를 자유롭게 생성하고 실행할 수 있다.
앱이 백그라운드로 들어가게 되면 몇분간은 여전히 서비스를 생성하고 사용할 수 있는 윈도우가 주어진다.
해당 윈도우가 끝나게되면 Idle 상태로 간주된다.
이때, 시스템은 마치 서비스의 Service.stopSelf()를 호출할 것 처럼 앱의 백그라운드 서비스를 중지한다.

White List

특정 상황에서 백그라운드 앱은 수분간 임시 whitelist에 등록된다.
앱이 whitelist에 있는 동안은 제한없이 서비스를 시작할 수 있으며 백그라운드 서비스가 실행되도록 허용된다.

예를 들면
* 높은 우선순위의 Firebase Cloud Messaging (FCM) 메시지를 처리할 때
* SMS/MMS 메시지와 같은 broadcast를 수신할 때
* Notification에서 PendingIntent를 실행할 때

JobScheduler

대부분의 경우 앱의 백그라운드 서비스는 JobScheduler job으로 교체될 수 있다.

예를 들어, CoolPhotoApp은 포그라운드에서 실행되지 않더라도, 친구가 공유한 사진을 수신했는지 여부를 확인해야 한다.
이전에 이 앱은 앱의 클라우드 저장소를 체크하는 백그라운드 서비스를 사용했다.
Android O 로 Migrate 하기위해 개발자는 백그라운드 서비스를 Schedule job으로 변경해서 주기적으로 실행해 서버에 쿼리를 날리고 종료하도록 했다.

Android O

Android O 이전에는 포그라운드 서비스를 만드는 일반적인 방법은 백그라운드 서비스를 만든 후 서비스를 포그라운드로 승격하는 것이다.
Android O를 사용하면, 앱이 현재 백그라운드 서비스를 만들 수 없는 경우에는 이 방법이 실패한다.

이러한 이유로, Android O는 새로운 Method인 NotificationManager.startServiceInForeground() 를 소개한다.
이 메소드를 호출하면 startService()를 호출한 것과 동일하게 서비스를 백그라운드에서 생성한 다음 즉시 서비스의 startForeground() 메소드를 호출하여 포그라운드로 승격시킨다.

이 서비스는 백그라운드가 아니기 때문에 백그라운드 서비스에 대한 제한이 적용되지 않는다.


Broadcast Limitations


앱이 Broadcast Receiver를 등록한다면, 앱은 Broadcast 가 보내질 때마다 리소스를 소모하게 된다.
만약, 앱이 System Event에 관련된 너무 많은 Broadcast Receiver를 등록한다면 문제의 원인이 될 수 있다.

이 문제를 완화시키기 위해 Android 7.0에서는 Background Optimization에 기술된 것처럼 Broradcast에 제한을 두었다.

Android O에서는 이 제한들을 좀 더 엄격하게 만들었다.

Android O 타겟으로 하는 앱들에만 적용됩니다.

  • 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()를 런타임에 사용할 수 있다.

JobScheduler

대부분의 경우, Implicit Broadcast를 위해 등록했던 앱들은 비슷한 기능을 JobScheduler job을 이용해서 작업을 수행할 수 있다.
예를 들어, 소셜 사진앱은 수시로 데이터를 정리해야 할 수 있으며 이 작업을 하기 위해 단말기 충전상태일 때를 선호한다.
이전에 앱은 Manifest에 ACTION_POWER_CONNECTED를 위한 Receiver를 등록했었다.
앱이 Broadcast를 받으면, 앱은 정리가 필요한지 확인한다.
Android O로 Migrate하기 위해 앱은 Manifest에서 Receiver를 제거한다. 대신에 앱은 단말이 Idle 상태에서 충전상태가 될 때 수행하는 정리 작업을 예약한다.

Implicit Broadcast Exception

일부 Implicit Broadcast는 이 제한에 해당되지 않는다.
앱은 Target API Level에 상관없이 Broadcast를 Manifest에 등록할 수 있다.
예외 Broadcast 목록은 암시적 브로드캐스트 예외에서 확인할 수 있다.


Migration Guide


Background Service Limitations

  • 백그라운드 서비스를 만들어서 포어그라운드로 승격시키려 하지 말고 새로운 메소드인 NotificationManager.startServiceInForeground()를 사용해라

  • 서비스를 사용자에게 알려지게 하려면 포어그라운드 서비스로 만들어라. 서비스를 만들기 위해 startService() 대신 NotificationManager.startServiceInForeground()를 사용해라

  • 서비스 기능을 Scheduled job을 이용해 복제할 방법을 찾아라

  • 백그라운드에서 폴링하는 대신 네트워크 이벤트가 발생할 때 FCM을 이용해 선택적으로 앱을 깨워라

Broadcast Limitations

  • Receiver를 Manifest에서 선언하지 말고 Context.registerReceiver()를 이용해 Runtime에 생성해라

  • Implicit Broadcast 를 트리거한 Condition을 체크하기 위해 Scheduled job을 이용해라.

참고 사이트


Comments