구글콘솔로 부터 “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();
}