Android프로그래밍

[Android vitals] 비정상 종료 발생률 낮추려면? at android.app.ActivityThread.generateForegroundServiceDidNotStartInTimeException (ActivityThread.java:2134)

구글콘솔로 부터 “Android vitals bad behavior for 앱이름” 제목으로 메일이 수신되었다.

[메일 내용]

Emerging bad behavior
Your Android vitals user-perceived crash rate is 1.42% which exceeds the bad behavior threshold of 1.09% in the last 7 days period. If your metric persists at this level, your app is likely to become less discoverable and a warning is likely to be shown on your store listing.Improve your app quality to reduce your bad behaviour threshold.


[번역 내용]

발생하는 문제 행동

귀하의 Android Vitals 사용자 인지 충돌률이 1.42%로, 지난 7일 동안의 문제 행동 임계값인 1.09%를 초과했습니다. 이 수치가 지속되면 앱의 검색 노출이 줄어들 가능성이 있으며, 스토어 등록 정보에 경고가 표시될 가능성이 있습니다.

앱 품질을 개선하여 문제 행동 임계값을 낮추세요.

임계값 기준이 1.09%인데, 그 수치를 넘어선 것이다.


비정상 종료 및 ANR 메뉴를 클릭하여 지난 28일기준으로 비정상 종료 케이스를 찾아보았다.

상세내용을 살펴보니, 안드로이드 13이 설치된 휴대전화에서 발생되었다.

오류 내용은 다음과 같다.

Exception android.app.RemoteServiceException$ForegroundServiceDidNotStartInTimeException:
  at android.app.ActivityThread.generateForegroundServiceDidNotStartInTimeException (ActivityThread.java:2134)
  at android.app.ActivityThread.throwRemoteServiceException (ActivityThread.java:2108)
  at android.app.ActivityThread.-$$Nest$mthrowRemoteServiceException (Unknown Source)
  at android.app.ActivityThread$H.handleMessage (ActivityThread.java:2370)
  at android.os.Handler.dispatchMessage (Handler.java:106)
  at android.os.Looper.loopOnce (Looper.java:211)
  at android.os.Looper.loop (Looper.java:300)
  at android.app.ActivityThread.main (ActivityThread.java:8324)
  at java.lang.reflect.Method.invoke
  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:581)
  at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1028)
Caused by android.app.StackTrace: Last startServiceCommon() call for this service was made here
  at android.app.ContextImpl.startServiceCommon (ContextImpl.java:1925)
  at android.app.ContextImpl.startForegroundService (ContextImpl.java:1880)
  at android.content.ContextWrapper.startForegroundService (ContextWrapper.java:832)
  at android.content.ContextWrapper.startForegroundService (ContextWrapper.java:832)
  at com.google.firebase.messaging.a.o (SourceFile:1)
  at com.test.charger.GeneralActivity.s (SourceFile:112)
  at com.test.charger.GeneralActivity.onCreate (SourceFile:1048)
  at android.app.Activity.performCreate (Activity.java:8547)
  at android.app.Activity.performCreate (Activity.java:8511)
  at android.app.Instrumentation.callActivityOnCreate (Instrumentation.java:1437)
  at android.app.ActivityThread.performLaunchActivity (ActivityThread.java:3877)
  at android.app.ActivityThread.handleLaunchActivity (ActivityThread.java:4042)
  at android.app.servertransaction.LaunchActivityItem.execute (LaunchActivityItem.java:101)
  at android.app.servertransaction.TransactionExecutor.executeCallbacks (TransactionExecutor.java:135)
  at android.app.servertransaction.TransactionExecutor.execute (TransactionExecutor.java:95)
  at android.app.ActivityThread$H.handleMessage (ActivityThread.java:2436)


왜 발생하는가?

안드로이드 13에서 발생하는 ForegroundServiceDidNotStartInTimeException 오류는 포그라운드 서비스가 정해진 시간 내에 시작되지 않았을 때 발생한다. 이 문제는 주로 포그라운드 서비스가 startForegroundService()를 호출한 후 10초 이내에 startForeground()를 호출하지 않았을 때 발생한다.


휴대폰 마다 백그라운드 서비스 허용 갯수가 달라서 이미 다른 앱들이 백그라운드 서비스를 사용중이면 이렇게 10초이내에 호출되지 못하는 것인가?


[해결방법]

서비스가 시작될 때 시간이 오래 걸리는 작업이 있다면, 해당 작업을 최적화하거나 비동기적으로 처리하는 것이 중요한데, 오래 걸리는 작업이 없는데…… 호출지연이 발생되는 것으로 보인다.


백그라운드 작업 분리: 시간이 오래 걸리는 작업은 별도의 스레드에서 처리하여 startForeground() 호출이 지연되지 않도록 한다.


포그라운드 서비스 우선순위 설정:
포그라운드 서비스의 우선순위를 높이기 위해 startForeground() 호출 시 Notification의 우선순위를 높일 수 있다.

Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
        .setContentTitle("서비스 실행 중")
        .setContentText("포그라운드 서비스가 실행 중입니다.")
        .setSmallIcon(R.drawable.ic_notification)
        .setPriority(NotificationCompat.PRIORITY_HIGH) // 우선순위를 높임
        .build();

내 앱의 문제점은?

중국에서 만든 샤오미 폰 등에서 대부분 발생하는 문제이다.

백그라운드 제한 우회

샤오미 폰에서는 백그라운드 제한을 우회하기 위해 다음과 같은 추가 설정을 확인해야 한다:

  • 설정 > 앱 > 앱 관리 > [앱 이름] > 배터리 절약 > 제한 없음으로 설정
  • 설정 > 앱 > 앱 관리 > [앱 이름] > 자동 시작을 활성화


자동 시작 활성화

샤오미 폰에서는 앱이 설치되면 기본적으로 “자동 시작”이 비활성화 된다. 사용자가 수동으로 활성화해야 한다. 이를 위해 다음과 같이 안내할 수 있다:

Intent intent = new Intent();
intent.setComponent(new ComponentName(
    "com.miui.securitycenter",
    "com.miui.permcenter.autostart.AutoStartManagementActivity"
));

try {
    startActivity(intent);
} catch (Exception e) {
    // MIUI가 아닌 경우 또는 액티비티를 찾을 수 없는 경우
    e.printStackTrace();
}
error: Content is protected !!