2011年8月3日水曜日

Serviceの強制終了

(2011/11/22 こちらのエントリーにじゃあどーすんのよ?について、やってみたことを書いてみました)

Serviceは、Androidシステムによって、終了させられてしまうことがあります。
bindしているActivityが全ていなくなったとか、Low Memoryになったとか。

Serviceには、onDestroy()も、onLowMemory()も存在してますので、
終了させられても、この2つをちゃんと実装しておけば良い・・・

と思いきや、

そんなの呼ばれずにKillされてしまうシチュエーションがあります。
ちょっとググれば、LowMemoryでは、そうなってしまうことがあるようなことがわかりますが、それだけではありません。

だれもそのServiceにbindしてない状態ですと、LowMemoryとか関係なく、一定時間経つとKillされます。
定期的に処理を行っていたとしても、本当に、Killされちゃいます。
onDestroyとか一切呼ばれません。

ServiceがKillされちゃうあたりで、"No longer want xx.service (pid xxxxx): hidden #xx"といったLogが出てきますが、このLogがあるのがframework/base/services/ActivityManagerService.java です。

コードを覗いてみると(12/24版のGingerBread)、
12170行目に、このLogをだしてます。そのちょっと下、12175行目で、やはり、います。
ProcessのKillが。

if (app.curAdj >= HIDDEN_APP_MIN_ADJ) {
  if (!app.killedBackground) {
    numHidden++;
    if (numHidden > MAX_HIDDEN_APPS) {
      Slog.i(TAG, "No longer want " + app.processName
               + " (pid " + app.pid + "): hidden #" + numHidden);
      EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
               app.processName, app.setAdj, "too many background");
      app.killedBackground = true;
      Process.killProcessQuiet(app.pid);
    }
  }
}
これでは、onDestroyも呼ばれないのも納得・・・
この動作を避けるためには、Service::startForeground()を、必要なタイミングで呼べばいいです。
実際、ActivityManagerServiceでも、Foreground ServiceはKillしないようにしてます(※)

(※)正確には、Killされにくくなる、みたいです。どれから順番にKillするかはcomputeOomAdjLocked()を読めば良さそう。

Notification notification = new Notification(R.drawable.icon,
getString(R.string.StartNotification),
System.currentTimeMillis());

Intent t_intent = new Intent(this, Target.class);

t_intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent intent = PendingIntent.getActivity(this, 0,
t_intent,0);
notification.setLatestEventInfo(this,
getString(R.string.app_name),
getString(R.string.Notification), intent);
notification.flags = Notification.FLAG_ONGOING_EVENT;

startForeground(FORGROUND_ID, notification);
Notificationが必要なので、それを作って、startForeground()を呼んであげます。startForeground()の第1引数はNotificationに渡す識別用のIDです。


これで、たいていのシチュエーションではKillされないと思います。
が、ServiceのAPI仕様書にもありますが、Critical な Low Memory状態だと、今画面に出てるActivityから
使われてても、ServiceがKillされるようなこともあるらしいので(気にしなくていいらしいけど)、
Killされる可能性があるというのは、頭の片隅においてServiceを設計したほうが良さそうです。

0 件のコメント:

コメントを投稿