做实验如下:
C:\>adb shell ps |grep android.process.media app_14 817 197 107556 24456 ffffffff afd0c74c S android.process.media F:\send_file>adb shell kill 817 F:\send_file>adb logcat
仔细查看MediaScannserService.java代码如下,因此每条命令执行后均将执行stopSelf(),因此当crash进程被发现时,如果Scan已结束则media进程被重启。如果crash时scan尚未结束,则scheduleServiceRestartLocked被调用。
private final class ServiceHandler extends Handler { @Override public void handleMessage(Message msg) { ... stopSelf(msg.arg1); }
public final void stopSelf(int startId) { if (mActivityManager == null) { return; } try { mActivityManager.stopServiceToken( new ComponentName(this, mClassName), mToken, startId); } catch (RemoteException ex) { } }
而stopServiceToken当遇到请求stopService时,仅当startId为最后一次请求的id时才真正close Service。
ActivityManagerService.java
public boolean stopServiceToken(ComponentName className, IBinder token, int startId) { synchronized(this) { if (DEBUG_SERVICE) Slog.v(TAG, "stopServiceToken: " + className + " " + token + " startId=" + startId); ServiceRecord r = findServiceLocked(className, token); if (r != null) { if (startId >= 0) { // Asked to only stop if done with all work. Note that // to avoid leaks, we will take this as dropping all // start items up to and including this one. ServiceRecord.StartItem si = r.findDeliveredStart(startId, false); if (si != null) { while (r.deliveredStarts.size() > 0) { ServiceRecord.StartItem cur = r.deliveredStarts.remove(0); cur.removeUriPermissionsLocked(); if (cur == si) { break; } } } if (r.lastStartId != startId) { //只有当最后start的id才可触发关闭Service return false; } } synchronized (r.stats.getBatteryStats()) { r.stats.stopRunningLocked(); r.startRequested = false; r.callStart = false; } final long origId = Binder.clearCallingIdentity(); bringDownServiceLocked(r, false); //去掉Service记录 Binder.restoreCallingIdentity(origId); return true; } } return false; }
如果在MediaScanner扫描媒体文件时android.process.media发生crash,则由于此时MediaScannerService正在运行,故ActivityManagerService将重启android.process.media进程并启动MediaScannerService。
至于进程中的Provider,即使有用户正在使用但Provider均已完成publish,则进程crash后ActivityManagerService并不会重启该进程。一旦进程被启动,其中的Provider将被自动运行。