前回のエントリのサンプルコードで、LowBatteryの場合と、電源キー押しでのShutdownの場合に、ACTION_SHUTDOWNのBroadcast Intentが投げられることがわかりました。
これを拾って、終了処理をすればよいわけですが、ふと疑問に思います。
「終了処理で、無限ループに陥ったら、どうなるの?」
前回のサンプルコードで、onShutdown()に無限ループのコードを入れたところ・・・端末は正常に?終了しました。
onStop()/onDestroy()にも入れてみましたが、同じ動作です。
なんだか怪しいので、こちらを参考に、Shutdown処理を追ってみました。
ShutdownThread.javaの213行目(Gingerbread 12/23版の場合)で、Broadcast Intentを発行しています。
以下、抜粋。
Log.i(TAG, "Sending shutdown broadcast...");
// First send the high-level shut down broadcast.
mActionDone = false;
mContext.sendOrderedBroadcast(new Intent(Intent.ACTION_SHUTDOWN), null,
br, mHandler, 0, null, null);
final long endTime = SystemClock.elapsedRealtime() + MAX_BROADCAST_TIME;
synchronized (mActionDoneSync) {
while (!mActionDone) {
long delay = endTime - SystemClock.elapsedRealtime();
if (delay <= 0) {
Log.w(TAG, "Shutdown broadcast timed out");
break;
}
try {
mActionDoneSync.wait(delay);
} catch (InterruptedException e) {
}
}
}
Log.i(TAG, "Shutting down activity manager...");
final IActivityManager am =
ActivityManagerNative.asInterface(ServiceManager.checkService("activity"));
if (am != null) {
try {
am.shutdown(MAX_BROADCAST_TIME);
} catch (RemoteException e) {
}
}
mActionDonwSync.wait()は、ACTION_SHUTDOWNのBroadcast Intent発行が終わると戻ってきますので、発行しただけでam.shutdown()に入ります。IActivityManagerはリモートインターフェースですが、リモートの先はframeworks/base/services/java/com/android/server/am/ActivityManagerService.javaです。
ActivityManagerService::shutdown()はどのようになっているかというと。
public boolean shutdown(int timeout) {
if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires permission "
+ android.Manifest.permission.SHUTDOWN);
}
boolean timedout = false;
synchronized(this) {
mShuttingDown = true;
mWindowManager.setEventDispatching(false);
if (mMainStack.mResumedActivity != null) {
mMainStack.pauseIfSleepingLocked();
final long endTime = System.currentTimeMillis() + timeout;
while (mMainStack.mResumedActivity != null
|| mMainStack.mPausingActivity != null) {
long delay = endTime - System.currentTimeMillis();
if (delay <= 0) {
Slog.w(TAG, "Activity manager shutdown timed out");
timedout = true;
break;
}
try {
this.wait();
} catch (InterruptedException e) {
}
}
}
}
mUsageStatsService.shutdown();
mBatteryStatsService.shutdown();
return timedout;
}
これ以上追ってないので、推測が入りますが、Activityの終了を待ってはいるけど、timeout引数で指定されてきた時間が過ぎると、Activityの終了をまたなくなる、あきらめちゃう、ということになると思います。あきらめた後は、、、System系のServiceの停止や、ファイルシステムのアンマウントが始まるようなので、終了できなかったアプリは、動作が不安定になって最終的にKillされちゃうだけかなと。
なお、このTimeoutは、ShutdownThread.javaのMAX_BROADCAST_TIMEで指定されている時間で、Android Originalソースだと10秒になっていました。
MAX_BROADCAST_TIMEの10秒、というのは、単一のアプリからするとかなり長いですが、ほかにShutdown、終了処理をするアプリもいる訳なので、あまり悠長に処理をしてられる余裕もないのかも。
Shutdownで処理をする場合は、間に合わなくなる可能性も考えて、重要なデータから退避するとか、そもそもKillされる前提で設計した方がいいのかな、と思います。
・・・少し考えすぎているような気もしますが、そーいうこともあるのかな、と、頭の片隅に入れておきます。
0 件のコメント:
コメントを投稿