前回のエントリのサンプルコードで、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 件のコメント:
コメントを投稿