Android Gems — AMS的Service生命周期管理
Posted threepigs
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android Gems — AMS的Service生命周期管理相关的知识,希望对你有一定的参考价值。
Service对于android开发来说再熟悉不过了,不过大部分人对Service的了解也仅限于api,这篇文章,我们通过分析AMS的源码,从一个更高的高度来了解一下Service的整个生命周期。
Service的生命周期接口:
1. startService
2. bindService
3. stopService
4. unbindService
这几个接口在apk进程里调用,通过ActivityManagerNative这个Binder最后调用到ActivityManagerService里,而AMS管理Service的类是ActiveService,这个类接管了所有Service生命周期的函数,包括startServiceLocked、stopServiceLocked、bindServiceLocked、unbindServiceLocked等。
startServiceLocked:
该函数实现Service的启动,首先调用retrieveServiceLocked根据Intent查询ServiceLookupResult(主要字段ServiceRecord),查询是先在ServiceMap里找,没有就重新由PackageManager的resolveService来获得ResolveInfo,创建新的ServiceRecord。针对Service的case,startService分为下面三种case,1,caller app是前台应用或者Service所在的app的进程优先级较高(高于PROCESS_STATE_SERVICE), 那么无限制的start。2,其他情况的Service作为background service,会加入到mStartingBackground list里,如果starting list的size没有达到上限,那么直接启动。3,此时starting list已到上限,那么此Service的start会推迟,Service会加到mDelayedStartList里。
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
int callingPid, int callingUid, String callingPackage, int userId)
throws TransactionTooLargeException
......
......
// 检查caller app是否是前台进程
final boolean callerFg;
if (caller != null)
final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
if (callerApp == null)
throw new SecurityException(
"Unable to find app for caller " + caller
+ " (pid=" + Binder.getCallingPid()
+ ") when starting service " + service);
callerFg = callerApp.setSchedGroup != Process.THREAD_GROUP_BG_NONINTERACTIVE;
else
callerFg = true;
// 查找ServiceRecord
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType, callingPackage,
callingPid, callingUid, userId, true, callerFg);
......
......
ServiceRecord r = res.record;
......
......
r.lastActivity = SystemClock.uptimeMillis();
r.startRequested = true;
r.delayedStop = false;
r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
service, neededGrants));
final ServiceMap smap = getServiceMap(r.userId);
boolean addToStarting = false;
if (!callerFg && r.app == null && mAm.mStartedUsers.get(r.userId) != null)
ProcessRecord proc = mAm.getProcessRecordLocked(r.processName, r.appInfo.uid, false);
if (proc == null || proc.curProcState > ActivityManager.PROCESS_STATE_RECEIVER)
// 这个分支表示Service所在的进程不存在,或者进程优先级小于PROCESS_STATE_RECEIVER,说明这个Service是background service
......
// 如果Service在delayed start list,则直接返回
if (r.delayed)
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "Continuing to delay: " + r);
return r.name;
// 如果后starting background list超上限,则加到mDelayedStartList,暂时不startService,直接返回
if (smap.mStartingBackground.size() >= mMaxStartingBackground)
// Something else is starting, delay!
Slog.i(TAG_SERVICE, "Delaying start of: " + r);
smap.mDelayedStartList.add(r);
r.delayed = true;
return r.name;
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "Not delaying: " + r);
addToStarting = true;
else if (proc.curProcState >= ActivityManager.PROCESS_STATE_SERVICE)
// 这个分支表示Service所在的进程优先级小于PROCESS_STATE_SERVICE,但又比PROCESS_STATE_RECEIVER大,加到starting list里,并startService
addToStarting = true;
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
"Not delaying, but counting as bg: " + r);
else if (DEBUG_DELAYED_STARTS)
StringBuilder sb = new StringBuilder(128);
sb.append("Not potential delay (state=").append(proc.curProcState)
.append(' ').append(proc.adjType);
String reason = proc.makeAdjReason();
if (reason != null)
sb.append(' ');
sb.append(reason);
sb.append("): ");
sb.append(r.toString());
Slog.v(TAG_SERVICE, sb.toString());
......
......
// 分支走到这里等于startService会成功,addToStarting表示是否加到StartingBackground List
return startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
Service的start是由函数startServiceInnerLocked完成,而startServiceInnerLocked则是调用bringUpServiceLocked完成Service的start,每次startService都会往ServiceRecord的pendingStarts里填加一项StartItem,即使是被放入Delayed List的Service启动。bringUpServiceLocked做的事就是拉起Service。
一,如果进程r.app和r.app.thread已经初始化(代表着Service之前已经Create过),那么bringUpServiceLocked只需要执行onStartCommand,这是通过调用sendServiceArgsLocked来实现,sendServiceArgsLocked就遍历之前pendingStarts的所有StartItem(每个startService都会对应一个StartItem),逐个调用app.thread.scheduleServiceArgs。app.thread是Service所在进程的IApplicationThread Binder对象,用于AMS的SystemServer进程到Client App端的跨进程调用,IApplicationThread的实现是在ActivityThread的内部类ApplicationThread,AMS -> ActivityThread的调用通过IApplicationThread,ActivityThread -> AMS的调用就是ActivityManagerNative,这样就打通了一条从AMS到ActivityThread的跨进程调用之路。scheduleServiceArgs在ActivityThread里的对应就是ActivityThread.handleServiceArgs,这就执行到了我们所熟悉的onStartCommand。至此可以解释两个我们对于Service的认知:1,每次startService,都会对应一次onStartCommand,就算Service已经onCreate成功。2,Service的回调函数都是在主线程,这个和ApplicationThread这个Binder Client的执行线程一致。sendServiceArgsLocked之后,pendingStarts里的StartItem就被加入到了deliveredStarts里,等待后续stopService或者Service restart的时候用。
二,如果Service所在的进程已经创建(ProcessRecord不空),那么会调用realStartServiceLocked来启动Service,这时的Service是还没有调用过onCreate。realStartServiceLocked会调用app.thread.scheduleCreateService来完成Service的启动,scheduleCreateService同scheduleServiceArgs一样,会调用到ActivityThread里,最终会执行Service的onCreate。之后同样执行sendServiceArgsLocked回调到onStartCommand。
三,如果Service所在的进程还未创建,那么bringUpServiceLocked做的事就是调用AMS的startProcessLocked创建进程,并将Service放进mPendingServices,等待进程创建成功,调用attachApplicationLocked的时候,会遍历所有的mPendingServices,继续调用realStartServiceLocked来完成Service的启动。
最后再看看bringUpServiceLocked的代码来加深一下印象
private final String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
boolean whileRestarting) throws TransactionTooLargeException
// Service已经启动过了,直接调用sendServiceArgsLocked来执行onStartCommand
if (r.app != null && r.app.thread != null)
sendServiceArgsLocked(r, execInFg, false);
return null;
// Service正在restart,啥都不做,等restart定时器触发以后再start
if (!whileRestarting && r.restartDelay > 0)
// If waiting for a restart, then do nothing.
return null;
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Bringing up " + r + " " + r.intent);
// 从正在重启的Service列表里删除
if (mRestartingServices.remove(r))
r.resetRestartCounter();
clearRestartingIfNeededLocked(r);
// 已经start了,从mDelayedStartList里删除
if (r.delayed)
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "REM FR DELAY LIST (bring up): " + r);
getServiceMap(r.userId).mDelayedStartList.remove(r);
r.delayed = false;
......
......
final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
final String procName = r.processName;
ProcessRecord app;
if (!isolated)
app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
if (DEBUG_MU) Slog.v(TAG_MU, "bringUpServiceLocked: appInfo.uid=" + r.appInfo.uid
+ " app=" + app);
// 如果进程已经创建,那么可以执行startService了,先执行Service的onCreate,再执行onStartCommand
if (app != null && app.thread != null)
try
app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
realStartServiceLocked(r, app, execInFg);
return null;
catch (TransactionTooLargeException e)
throw e;
catch (RemoteException e)
Slog.w(TAG, "Exception when starting service " + r.shortName, e);
// If a dead object exception was thrown -- fall through to
// restart the application.
else
// If this service runs in an isolated process, then each time
// we call startProcessLocked() we will get a new isolated
// process, starting another process if we are currently waiting
// for a previous process to come up. To deal with this, we store
// in the service any current isolated process it is running in or
// waiting to have come up.
app = r.isolatedProc;
// 如果进程还没创建,调用startProcessLocked来创建进程,并加入到mPendingServices,等待attachApplicationLocked后再startService
if (app == null)
if (app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
"service", r.name, false, isolated, false)) == null)
String msg = "Unable to launch app "
+ r.appInfo.packageName + "/"
+ r.appInfo.uid + " for service "
+ r.intent.getIntent() + ": process is bad";
Slog.w(TAG, msg);
bringDownServiceLocked(r);
return msg;
if (isolated)
r.isolatedProc = app;
if (!mPendingServices.contains(r))
mPendingServices.add(r);
if (r.delayedStop)
// Oh and hey we've already been asked to stop!
r.delayedStop = false;
if (r.startRequested)
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
"Applying delayed stop (in bring up): " + r);
stopServiceLocked(r);
return null;
bindServiceLocked :
bindServiceLocked比startService要复杂很多,主要是其多了Service和App之间的绑定关系:
1,AppBindRecord
retrieveServiceLocked查找到ServiceRecord之后,生成Service和Client(callerApp)之间的绑定关系AppBindRecord,AppBindRecord的字段包括service,client,intent,确定了他们之间的绑定关系。
final class AppBindRecord
final ServiceRecord service; // The running service.
final IntentBindRecord intent; // The intent we are bound to.
final ProcessRecord client; // Who has started/bound the service.
2,ConnectionRecord
Service和Client之间一个绑定关系就会对应一个ConnectionRecord,ConnectionRecord字段里除了绑定关系等对象之外,还有一个比较重要的对象就是IServiceConnection,这是一个binder对象,用做Client端和Server端的桥接,IServiceConnection的定义在LoadedApk里,处理ServiceConnection的connected状态,并由ServiceDispatcher统一做Service连接分发,如果connected函数的第二个参数IBinder是空,那么就是调用回调函数onServiceDisconnected,不空则表示连接建立成功,调用onServiceConnected。在ServiceConnection创建成功时,ServiceDispatcher会注册这个Service的死亡通知,如果Service crash,也会马上调用onServiceDisconnected。
private static class InnerConnection extends IServiceConnect.Stub
final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;
InnerConnection(LoadedApk.ServiceDispatcher sd)
this.mDispatcher = new WeakReference(sd);
public void connected(ComponentName name, IBinder service) throws RemoteException
LoadedApk.ServiceDispatcher sd = (LoadedApk.ServiceDispatcher)this.mDispatcher.get();
if(sd != null)
sd.connected(name, service);
static final class ServiceDispatcher
public void connected(ComponentName name, IBinder service)
if(this.mActivityThread != null)
this.mActivityThread.post(new LoadedApk.ServiceDispatcher.RunConnection(name, service, 0));
else
this.doConnected(name, service);
public void death(ComponentName name, IBinder service)
synchronized(this)
this.mDied = true;
LoadedApk.ServiceDispatcher.ConnectionInfo old = (LoadedApk.ServiceDispatcher.ConnectionInfo)this.mActiveConnections.remove(name);
if(old == null || old.binder != service)
return;
old.binder.unlinkToDeath(old.deathMonitor, 0);
if(this.mActivityThread != null)
this.mActivityThread.post(new LoadedApk.ServiceDispatcher.RunConnection(name, service, 1));
else
this.doDeath(name, service);
public void doConnected(ComponentName name, IBinder service)
LoadedApk.ServiceDispatcher.ConnectionInfo old;
synchronized(this)
if(this.mForgotten)
return;
old = (LoadedApk.ServiceDispatcher.ConnectionInfo)this.mActiveConnections.get(name);
if(old != null && old.binder == service)
return;
if(service != null)
this.mDied = false;
LoadedApk.ServiceDispatcher.ConnectionInfo info = new LoadedApk.ServiceDispatcher.ConnectionInfo();
info.binder = service;
info.deathMonitor = new LoadedApk.ServiceDispatcher.DeathMonitor(name, service);
try
service.linkToDeath(info.deathMonitor, 0);
this.mActiveConnections.put(name, info);
catch (RemoteException var8)
this.mActiveConnections.remove(name);
return;
else
this.mActiveConnections.remove(name);
if(old != null)
old.binder.unlinkToDeath(old.deathMonitor, 0);
if(old != null)
this.mConnection.onServiceDisconnected(name);
if(service != null)
this.mConnection.onServiceConnected(name, service);
public void doDeath(ComponentName name, IBinder service)
this.mConnection.onServiceDisconnected(name);
private final class DeathMonitor implements DeathRecipient
final ComponentName mName;
final IBinder mService;
DeathMonitor(ComponentName name, IBinder service)
this.mName = name;
this.mService = service;
public void binderDied()
ServiceDispatcher.this.death(this.mName, this.mService);
3,connections
AppBindRecord的connections字段则保存了这个client的所有ServiceConnection连接ConnectionRecord,ConnectionRecord和IServiceConnection对象是对应的。ServiceRecord也有个connections列表,但ServiceRecord的connections列表存储的是这个Service相关的所有ConnectionRecord,Service和Client之间是多对多的关系,所以其各自维护了一个connections。ConnectionRecord和AppBindRecord初始化完之后,就进入Service的主题,如果bindService的flag加上了BIND_AUTO_CREATE,那么将马上调用bringUpServiceLocked来启动Service,否则不会主动startService,这种情况如果之前Service并没有启动过,那么bind操作就会失败。之后检查Service是否绑定过,没有绑定过或者需要重新绑定的时候,由requestServiceBindingLocked来实际bindService,最后通过app.thread.scheduleBindService完成Service的绑定。并通过c.conn.connected调用,通知Client的IServiceConnection.onServiceConnected。从而完成Service和Client之间的Bind。
stopServiceLocked:
private void stopServiceLocked(ServiceRecord service)
// 如果Service还未start,那么置delayedStop为true,等startService结束以后调用stopServiceLocked
if (service.delayed)
// If service isn't actually running, but is is being held in the
// delayed list, then we need to keep it started but note that it
// should be stopped once no longer delayed.
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "Delaying stop of pending: " + service);
service.delayedStop = true;
return;
synchronized (service.stats.getBatteryStats())
service.stats.stopRunningLocked();
service.startRequested = false;
if (service.tracker != null)
service.tracker.setStarted(false, mAm.mProcessStats.getMemFactorLocked(),
SystemClock.uptimeMillis());
service.callStart = false;
bringDownServiceIfNeededLocked(service, false, false);
stopServiceLocked是调用bringDownServiceLocked来停止Service。首先对这个Service的所有bind连接,都通知回调onServiceDisconnected,之后通过调用r.app.thread.scheduleStopService,通知Service进程stopService,Service的onDestroy会被调用。
private final void bringDownServiceLocked(ServiceRecord r)
// 对这个Service的每个绑定连接都通知client端回调onServiceDisconnected
for (int conni=r.connections.size()-1; conni>=0; conni--)
ArrayList<ConnectionRecord> c = r.connections.valueAt(conni);
for (int i=0; i<c.size(); i++)
ConnectionRecord cr = c.get(i);
// There is still a connection to the service that is
// being brought down. Mark it as dead.
cr.serviceDead = true;
try
cr.conn.connected(r.name, null);
catch (Exception e)
Slog.w(TAG, "Failure disconnecting service " + r.name +
" to connection " + c.get(i).conn.asBinder() +
" (in " + c.get(i).binding.client.processName + ")", e);
// 通过scheduleUnbindService,通知Service进程回调onBind
if (r.app != null && r.app.thread != null)
for (int i=r.bindings.size()-1; i>=0; i--)
IntentBindRecord ibr = r.bindings.valueAt(i);
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Bringing down binding " + ibr
+ ": hasBound=" + ibr.hasBound);
if (ibr.hasBound)
try
bumpServiceExecutingLocked(r, false, "bring down unbind");
mAm.updateOomAdjLocked(r.app);
ibr.hasBound = false;
r.app.thread.scheduleUnbindService(r,
ibr.intent.getIntent());
catch (Exception e)
Slog.w(TAG, "Exception when unbinding service "
+ r.shortName, e);
serviceProcessGoneLocked(r);
// 已经unbind了,mPendingServices的列表可以清空了
for (int i=mPendingServices.size()-1; i>=0; i--)
if (mPendingServices.get(i) == r)
mPendingServices.remove(i);
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Removed pending: " + r);
r.cancelNotification();
r.isForeground = false;
r.foregroundId = 0;
r.foregroundNoti = null;
// Clear start entries.
r.clearDeliveredStartsLocked();
r.pendingStarts.clear();
if (r.app != null)
// 调用r.app.thread.scheduleStopService,通知Service进程stopService,Service的onDestroy会被调用
r.app.services.remove(r);
if (r.app.thread != null)
updateServiceForegroundLocked(r.app, false);
try
bumpServiceExecutingLocked(r, false, "destroy");
mDestroyingServices.add(r);
r.destroying = true;
mAm.updateOomAdjLocked(r.app);
r.app.thread.scheduleStopService(r);
catch (Exception e)
Slog.w(TAG, "Exception when destroying service "
+ r.shortName, e);
serviceProcessGoneLocked(r);
else
if (DEBUG_SERVICE) Slog.v(
TAG_SERVICE, "Removed service that has no process: " + r);
else
if (DEBUG_SERVICE) Slog.v(
TAG_SERVICE, "Removed service that is not running: " + r);
......
......
unbindService:
unbindService就比较简单了,把参数IServiceConnection对应的ConnectionRecord列表,逐个调用removeConnectionLocked移除连接,而removeConnectionLocked其实就是之前bindService时初始化AppBindRecord相关对象的逆过程,把和这个需要unbind的IServiceConnection连接从各个数据结构里删掉。移除完之后,如果发现这个Service已经没有任何Client绑定在其上面,就会调用s.app.thread.scheduleUnbindService,通知Service的进程执行onUnbind。
boolean unbindServiceLocked(IServiceConnection connection)
IBinder binder = connection.asBinder();
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "unbindService: conn=" + binder);
ArrayList<ConnectionRecord> clist = mServiceConnections.get(binder);
if (clist == null)
Slog.w(TAG, "Unbind failed: could not find connection for "
+ connection.asBinder());
return false;
final long origId = Binder.clearCallingIdentity();
try
while (clist.size() > 0)
ConnectionRecord r = clist.get(0);
// 移除ConnectionRecord
removeConnectionLocked(r, null, null);
if (clist.size() > 0 && clist.get(0) == r)
// In case it didn't get removed above, do it now.
Slog.wtf(TAG, "Connection " + r + " not removed for binder " + binder);
clist.remove(0);
if (r.binding.service.app != null)
// This could have made the service less important.
if ((r.flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0)
r.binding.service.app.treatLikeActivity = true;
mAm.updateLruProcessLocked(r.binding.service.app,
r.binding.service.app.hasClientActivities
|| r.binding.service.app.treatLikeActivity, null);
// 重新更新各进程的oom_adj
mAm.updateOomAdjLocked(r.binding.service.app);
finally
Binder.restoreCallingIdentity(origId);
return true;
至此,我们介绍了AMS是怎么管理Service的整个生命周期,之前文章 Android的LowMemoryKiller杀进程策略 介绍LMK杀进程的时候,有个foreground的oom_adj级别对应的case就是executingServices的size大于0的情况,在Service的startService、stopService、bindService、unBindService的时候都会将Service加入到executingServices里,通过ServiceRecord.app.thread回调到Service的Client进程之后,都会调用ActivityManagerNative.getDefault().serviceDoneExecuting,执行到AMS进程里,再将这个Service从executingServices里删除。加到executingServices里之后,会有个超时时间(callerApp是前台的话是20秒,后台是200秒),超时则触发ANR。executingServices不空就表示,Service的生命周期还未走完,Service的Client进程还未收到回调,此时把其oom_adj下调到前台App的级别,以保证Service生命周期的完整性也是很合理的策略。
Service还有个特点是杀掉后是可以重启的,最后我们简单介绍一下这个重启策略。Service的死分为两种,一种是自己crash,一种是被LMK kill。Android进程刚创建的时候,ActivityManagerService在attachApplication方法里会注册该进程的死亡通知,所以不论那种死法,AMS都会通过死亡通知获得回调,从而根据一定的策略来重启进程。
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid)
......
......
try
AppDeathRecipient adr = new AppDeathRecipient(
app, pid, thread);
thread.asBinder().linkToDeath(adr, 0);
app.deathRecipient = adr;
catch (RemoteException e)
app.resetPackageList(mProcessStats);
startProcessLocked(app, "link fail", processName);
return false;
......
......
AMS的死亡通知类定义如下:
private final class AppDeathRecipient implements IBinder.DeathRecipient
final ProcessRecord mApp;
final int mPid;
final IApplicationThread mAppThread;
AppDeathRecipient(ProcessRecord app, int pid,
IApplicationThread thread)
if (DEBUG_ALL) Slog.v(
TAG, "New death recipient " + this
+ " for thread " + thread.asBinder());
mApp = app;
mPid = pid;
mAppThread = thread;
@Override
public void binderDied()
if (DEBUG_ALL) Slog.v(
TAG, "Death received in " + this
+ " for thread " + mAppThread.asBinder());
synchronized(ActivityManagerService.this)
appDiedLocked(mApp, mPid, mAppThread, true);
一旦进程死掉,就会调用appDiedLocked来处理,如果是Home App挂了的话,进程就会马上重启。
final void appDiedLocked(ProcessRecord app, int pid, IApplicationThread thread,
boolean fromBinderDied)
// First check if this ProcessRecord is actually active for the pid.
synchronized (mPidsSelfLocked)
ProcessRecord curProc = mPidsSelfLocked.get(pid);
if (curProc != app)
Slog.w(TAG, "Spurious death for " + app + ", curProc for " + pid + ": " + curProc);
return;
BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
synchronized (stats)
stats.noteProcessDiedLocked(app.info.uid, pid);
if (!app.killed)
// 如果不是死亡通知调用的,那么就执行Process.killProcessQuiet杀死进程
if (!fromBinderDied)
Process.killProcessQuiet(pid);
killProcessGroup(app.info.uid, pid);
app.killed = true;
// Clean up already done if the process has been re-started.
if (app.pid == pid && app.thread != null &&
app.thread.asBinder() == thread.asBinder())
boolean doLowMem = app.instrumentationClass == null;
boolean doOomAdj = doLowMem;
boolean homeRestart = false;
if (!app.killedByAm)
// 桌面App死了,需马上重启
if (mHomeProcessName != null && app.processName.equals(mHomeProcessName))
mHomeKilled = true;
homeRestart = true;
Slog.i(TAG, "Process " + app.processName + " (pid " + pid
+ ") has died");
mAllowLowerMemLevel = true;
else
// Note that we always want to do oom adj to update our state with the
// new number of procs.
mAllowLowerMemLevel = false;
doLowMem = false;
EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.userId, app.pid, app.processName);
if (DEBUG_CLEANUP) Slog.v(TAG_CLEANUP,
"Dying app: " + app + ", pid: " + pid + ", thread: " + thread.asBinder());
handleAppDiedLocked(app, false, true);
if (doOomAdj)
updateOomAdjLocked();
if (doLowMem)
doLowMemReportIfNeededLocked(app);
if (mHomeKilled && homeRestart)
// 立即重启Home App
Intent intent = getHomeIntent();
ActivityInfo aInfo = mStackSupervisor.resolveActivity(intent, null, 0, null, 0);
startProcessLocked(aInfo.processName, aInfo.applicationInfo, true, 0,
"activity", null, false, false, true);
homeRestart = false;
else if (app.pid != pid)
// A new process has already been started.
Slog.i(TAG, "Process " + app.processName + " (pid " + pid
+ ") has died and restarted (pid " + app.pid + ").");
EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.userId, app.pid, app.processName);
else if (DEBUG_PROCESSES)
Slog.d(TAG_PROCESSES, "Received spurious death notification for thread "
+ thread.asBinder());
handleAppDiedLocked会调用mServices.killServicesLocked,在killServicesLocked里会根据具体情况来实施重启策略,
final void killServicesLocked(ProcessRecord app, boolean allowRestart)
// 清除进程的所有Service connection
for (int i = app.connections.size() - 1; i >= 0; i--)
ConnectionRecord r = app.connections.valueAt(i);
removeConnectionLocked(r, app, null);
......
......
// Now do remaining service cleanup.
for (int i=app.services.size()-1; i>=0; i--)
ServiceRecord sr = app.services.valueAt(i);
// 除了persistent进程,其他的Service都清除,persitent是个高优先级的进程,不管oom_adj很小,LMK不会杀,
// 而且PackageManagerService在installApk的时候也不会杀掉,这样就会导致persistent的进程升级不了,必须要重启系统
if (!app.persistent)
app.services.removeAt(i);
// Sanity check: if the service listed for the app is not one
// we actually are maintaining, just let it drop.
final ServiceRecord curRec = smap.mServicesByName.get(sr.name);
if (curRec != sr)
if (curRec != null)
Slog.wtf(TAG, "Service " + sr + " in process " + app
+ " not same as in map: " + curRec);
continue;
// Service crash超过两次之后,Service被stop,不会再restart
if (allowRestart && sr.crashCount >= 2 && (sr.serviceInfo.applicationInfo.flags
&ApplicationInfo.FLAG_PERSISTENT) == 0)
Slog.w(TAG, "Service crashed " + sr.crashCount
+ " times, stopping: " + sr);
EventLog.writeEvent(EventLogTags.AM_SERVICE_CRASHED_TOO_MUCH,
sr.userId, sr.crashCount, sr.shortName, app.pid);
bringDownServiceLocked(sr);
else if (!allowRestart || !mAm.isUserRunningLocked(sr.userId, false))
bringDownServiceLocked(sr);
else
// 准备重启Service,重启的时间在scheduleServiceRestartLocked里设置
boolean canceled = scheduleServiceRestartLocked(sr, true);
// 如果stopIfKilled设为true,后续没有再调用startService的情况下,也不会再重启Service,调用bringDownServiceLocked停止Service
if (sr.startRequested && (sr.stopIfKilled || canceled))
if (sr.pendingStarts.size() == 0)
sr.startRequested = false;
if (sr.tracker != null)
sr.tracker.setStarted(false, mAm.mProcessStats.getMemFactorLocked(),
SystemClock.uptimeMillis());
if (!sr.hasAutoCreateConnections())
// Whoops, no reason to restart!
bringDownServiceLocked(sr);
......
......
// Make sure we have no more records on the stopping list.
int i = mDestroyingServices.size();
while (i > 0)
i--;
ServiceRecord sr = mDestroyingServices.get(i);
if (sr.app == app)
sr.forceClearTracker();
mDestroyingServices.remove(i);
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "killServices remove destroying " + sr);
app.executingServices.clear();
如果crash次数超过2次,那么进程死掉的时候,Service就不会进入restart状态。scheduleServiceRestartLocked是处理service restart的函数,确定每个要重启的service准备restart的时间点。可以看到persitent的进程的优先级非常高,除了没有crash超过2次的限制外,restartDelay的值也会被设为0,也就是说马上restart,所以一旦persistent进入循环重启状态的时候,就出现无限重启,根本听不下来。
Service的生命周期管理就介绍到这儿,代码主要分布在ActivityManagerService、ActiveService、ActivityThread、LoadedApk等类中,看完之后,对Service的原理的了解就更加深刻了。
作者简介:
田力,网易彩票Android端创始人,小米视频创始人,现任roobo技术经理、视频云技术总监
欢迎关注微信公众号 磨剑石,定期推送技术心得以及源码分析等文章,谢谢
以上是关于Android Gems — AMS的Service生命周期管理的主要内容,如果未能解决你的问题,请参考以下文章
Android的ActivityManagerService(简称AMS)的源码分析
Android的ActivityManagerService(简称AMS)的源码分析
Android的ActivityManagerService(简称AMS)的源码分析