後編?
startForegroundServiceしたあと5秒以内にstartForegroundしないと落ちるカラクリを説明します。
「なんのこと?」っていう人は前編から見て下さい。(まえおき、まとめ、だけ見れば多分イメージ湧きます)
実際にアプリを動かすとどんな感じになっているか?(再掲)
- JobScheduler(とか、それをラップしているGcmNetworkManager)から起動されるジョブサービスはちゃんと裏でも動ける
- でもそこからstartServiceやるとクラッシュ
- Activityから立ち上げたサービスはちゃんと起動できる
- でもActivityを閉じてしばらく経つと、サービスが勝手に終了する
- startForegroundServiceすれば、バックグラウンドからの起動でも死なない。でも
- 5秒以内にstartForegroundを呼ばないとクラッシュ
- startForegroundを呼ばずにstopSelf()してもクラッシュ
- IntentServiceの場合は、どこかでstartForeground呼ばないとクラッシュ
参考:Android Oからのバックグラウンド・サービスの制限事項を実演する。
ソースを読むぞ
startForegroundServiceしたあと5秒以内にstartForegroundしないと落ちるカラクリ
落ちるときのエラーログを手がかりに見ていきます。
E/AndroidRuntime: FATAL EXCEPTION: main
android.app.RemoteServiceException: Context.startForegroundService() did not then call Service.startForeground()
/frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
3358 void serviceForegroundTimeout(ServiceRecord r) {
3359 ProcessRecord app;
3360 synchronized (mAm) {
3361 if (!r.fgRequired || r.destroying) {
3362 return;
3363 }
3364
3365 if (DEBUG_BACKGROUND_CHECK) {
3366 Slog.i(TAG, "Service foreground-required timeout for " + r);
3367 }
3368 app = r.app;
3369 r.fgWaiting = false;
3370 stopServiceLocked(r);
3371 }
3372
3373 if (app != null) {
3374 mAm.mAppErrors.appNotResponding(app, null, null, false,
3375 "Context.startForegroundService() did not then call Service.startForeground()");
3376 }
3377 }
3378
3379 void serviceForegroundCrash(ProcessRecord app) {
3380 mAm.crashApplication(app.uid, app.pid, app.info.packageName, app.userId,
3381 "Context.startForegroundService() did not then call Service.startForeground()");
3382 }
2ヶ所ありますが、たぶん serviceForegroundTimeout
のほうでしょう。
タイムアウトを設定しているのは誰?
/frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
107 // How long the startForegroundService() grace period is to get around to
108 // calling startForeground() before we ANR + stop it.
109 static final int SERVICE_START_FOREGROUND_TIMEOUT = 5*1000;
...
3395 void scheduleServiceForegroundTransitionTimeoutLocked(ServiceRecord r) {
3396 if (r.app.executingServices.size() == 0 || r.app.thread == null) {
3397 return;
3398 }
3399 Message msg = mAm.mHandler.obtainMessage(
3400 ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG);
3401 msg.obj = r;
3402 r.fgWaiting = true;
3403 mAm.mHandler.sendMessageDelayed(msg, SERVICE_START_FOREGROUND_TIMEOUT);
3404 }
↑
sendServiceArgsLocked
↑
bingUpServiceLocked
↑
startServiceInnerLocked
↑・・・ここで前編に書いたForeground起動してるかチェックされてる
startServiceLocked
まとめ
Android 8.0対応、きついです・・・(まとまってないw