做实验如下:
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将被自动运行。