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 - AMS源码分析

Android的ActivityManagerService(简称AMS)的源码分析

Android的ActivityManagerService(简称AMS)的源码分析

Android的ActivityManagerService(简称AMS)的源码分析

Android的ActivityManagerService(简称AMS)的源码分析

Android ActivityManagerService (AMS)总结