Android源码分析 - Service的停止与重建

开篇

本篇以android-11.0.0_r25作为基础解析

在上一篇文章 Android源码分析 - Service启动流程 中,我们分析了一个Service是怎么启动的,这次我们再来看看一个Service是如何被停止的,什么情况下Service会被重建以及它的重建过程

流程图

由于Service的停止与重建在实际情况下会收到各种条件影响产生不同的情况,所以这里的流程图我也只画最简路径,以供大家参考

service主动停止流程图

service主动解绑流程图

Task移除流程图

service重建流程图

主动停止

首先,我们来看主动停止的情况,主动停止也分三种:

  • Service自己调用stopSelfstopSelfResult方法停止

  • 使用startService启动的Service,使用stopService方法停止

  • 使用bindService启动的Service,使用unbindService方法解除绑定,当没有任何ClientService绑定时,Service就会自行停止

Service.stopSelf 或 Service.stopSelfResult

stopSelfstopSelfResult方法唯一的区别是一个没返回值,一个会返回是否成功

//frameworks/base/core/java/android/app/Service.java
public final void stopSelf() {
    
    
    stopSelf(-1);
}

public final void stopSelf(int startId) {
    
    
    if (mActivityManager == null) {
    
    
        return;
    }
    try {
    
    
        mActivityManager.stopServiceToken(
                new ComponentName(this, mClassName), mToken, startId);
    } catch (RemoteException ex) {
    
    
    }
}

public final boolean stopSelfResult(int startId) {
    
    
    if (mActivityManager == null) {
    
    
        return false;
    }
    try {
    
    
        return mActivityManager.stopServiceToken(
                new ComponentName(this, mClassName), mToken, startId);
    } catch (RemoteException ex) {
    
    
    }
    return false;
}

这个方法也是直接调用了AMS.stopServiceToken方法

//frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
public boolean stopServiceToken(ComponentName className, IBinder token,
        int startId) {
    
    
    synchronized(this) {
    
    
        return mServices.stopServiceTokenLocked(className, token, startId);
    }
}

然后AMS转手调用了ActiveServices.stopServiceTokenLocked方法

//frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
boolean stopServiceTokenLocked(ComponentName className, IBinder token,
        int startId) {
    
    
    //通过className查找相应的ServiceRecord
    //在Service启动过程中调用的retrieveServiceLocked方法会查找Service,创建ServiceRecord
    //并将其添加到Map中,findServiceLocked方法只需要从这个Map中去获取即可
    ServiceRecord r = findServiceLocked(className, token, UserHandle.getCallingUserId());
    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.
            //查找startId所对应的已分发的启动项
            ServiceRecord.StartItem si = r.findDeliveredStart(startId, false, false);
            //从已分发启动请求列表中移除
            if (si != null) {
    
    
                while (r.deliveredStarts.size() > 0) {
    
    
                    ServiceRecord.StartItem cur = r.deliveredStarts.remove(0);
                    cur.removeUriPermissionsLocked();
                    if (cur == si) {
    
    
                        break;
                    }
                }
            }

            //如果传入的启动ID不是Service最后一次启动的ID,则不能停止服务
            //ps:每次启动Service,startId都会递增,初始值为1
            if (r.getLastStartId() != startId) {
    
    
                return false;
            }
        }

        ... //记录
        //重置启动状态(重要,后文中会分析)
        r.startRequested = false;
        r.callStart = false;
        final long origId = Binder.clearCallingIdentity();
        //接着停止Service
        bringDownServiceIfNeededLocked(r, false, false);
        Binder.restoreCallingIdentity(origId);
        return true;
    }
    return false;
}

startId机制

这里要说一下ServicestartId机制,每次启动Service时,ActiveServices.startServiceLocked方法会向ServiceRecord.pendingStarts列表中添加一个启动项ServiceRecord.StartItem,构建这个启动项需要提供一个startId,而这个startId是由ServiceRecord.makeNextStartId生成的

//frameworks/base/services/core/java/com/android/server/am/ServiceRecord.java
public int makeNextStartId() {
    
    
    lastStartId++;
    if (lastStartId < 1) {
    
    
        lastStartId = 1;
    }
    return lastStartId;
}

由于lastStartId的初始值为 0 ,所以第一次调用这个方法,得到的startId就是 1 ,即startId是从 1 开始递增的,由于当Service被停止后,ServiceRecord会从之前的缓存Map中移除,所以下一次再启动Service时会重新创建ServiceRecordstartId会被重置

当我们调用stopSelf停止服务时,如果传入了大于等于 0 的startId,此时便会判断这个startId是不是最后一次启动所对应的startId,如果不是的话,则不能停止这个Service

这个startId设计的意义是什么呢?我们从IntentService的设计中可以管中窥豹:

IntentService是一个运行在另一个线程的,每次处理完任务都会自动停止的Service,但如果你调用多次startService会发现,IntentService.onDestroy方法只会调用一次,这是为什么呢?因为IntentService每次停止,调用stopSelf方法都是带上这次启动的startId的,这样如果一次性有多个启动请求,前面的任务执行完,停止时发现,此次启动请求的startId不是最后一个startId,这样就不会停止掉自身,直到最后一个任务处理完成,避免了Service的多次停止启动消耗系统资源


接着,在这个方法的最后,调用bringDownServiceIfNeededLocked方法继续停止服务

//frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
private final void bringDownServiceIfNeededLocked(ServiceRecord r, boolean knowConn,
        boolean hasConn) {
    
    
    //检查此服务是否还被需要
    //在用stopSelf停止服务的这种情况下
    //检查的就是是否有auto-create的连接(flag为BIND_AUTO_CREATE)
    //如有则不能停止服务
    if (isServiceNeededLocked(r, knowConn, hasConn)) {
    
    
        return;
    }

    // Are we in the process of launching?
    //不要停止正在启动中的Service
    if (mPendingServices.contains(r)) {
    
    
        return;
    }

    //继续停止服务
    bringDownServiceLocked(r);
}

这个方法主要就做了一些能否停止服务的检查,主要的停止操作都在下一个bringDownServiceLocked方法中

//frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
private final void bringDownServiceLocked(ServiceRecord r) {
    
    
    ... //处理Client与Serivce的连接,进行断开连接以及解除绑定操作

    // Check to see if the service had been started as foreground, but being
    // brought down before actually showing a notification.  That is not allowed.
    //如果此Service是以前台服务的形式启动,并且当前还尚未成为前台服务
    if (r.fgRequired) {
    
    
        r.fgRequired = false;
        r.fgWaiting = false;
        ... //记录
        //将前台服务的超时回调取消
        mAm.mHandler.removeMessages(
                ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG, r);
        //这种情况直接令App崩溃,杀死应用
        if (r.app != null) {
    
    
            Message msg = mAm.mHandler.obtainMessage(
                    ActivityManagerService.SERVICE_FOREGROUND_CRASH_MSG);
            msg.obj = r.app;
            msg.getData().putCharSequence(
                ActivityManagerService.SERVICE_RECORD_KEY, r.toString());
            mAm.mHandler.sendMessage(msg);
        }
    }

    //记录销毁时间
    r.destroyTime = SystemClock.uptimeMillis();

    //从缓存中移除ServiceRecord
    final ServiceMap smap = getServiceMapLocked(r.userId);
    ServiceRecord found = smap.mServicesByInstanceName.remove(r.instanceName);

    // Note when this method is called by bringUpServiceLocked(), the service is not found
    // in mServicesByInstanceName and found will be null.
    if (found != null && found != r) {
    
    
        // This is not actually the service we think is running...  this should not happen,
        // but if it does, fail hard.
        //如果找到的服务不是我们目前停止的服务,应该是一个不可能的情况
        //碰到这种情况,将ServiceRecord重新放回去并抛出异常
        smap.mServicesByInstanceName.put(r.instanceName, found);
        throw new IllegalStateException("Bringing down " + r + " but actually running "
                + found);
    }
    //清除ServiceRecord
    smap.mServicesByIntent.remove(r.intent);
    r.totalRestartCount = 0;
    //取消之前的Service重启任务(如果有)
    unscheduleServiceRestartLocked(r, 0, true);

    // Also make sure it is not on the pending list.
    //从待启动Service列表中移除
    for (int i=mPendingServices.size()-1; i>=0; i--) {
    
    
        if (mPendingServices.get(i) == r) {
    
    
            mPendingServices.remove(i);
        }
    }

    //关闭前台服务通知
    cancelForegroundNotificationLocked(r);
    //对于已经成为前台服务的Service
    if (r.isForeground) {
    
    
        //修改应用的活动前台计数,如果计数小于等于0,将其从mActiveForegroundApps列表中移除
        decActiveForegroundAppLocked(smap, r);
        ... //更新统计信息
    }

    //各种清理操作
    r.isForeground = false;
    r.foregroundId = 0;
    r.foregroundNoti = null;
    r.mAllowWhileInUsePermissionInFgs = false;

    // Clear start entries.
    r.clearDeliveredStartsLocked();
    r.pendingStarts.clear();
    smap.mDelayedStartList.remove(r);

    if (r.app != null) {
    
    
        synchronized (r.stats.getBatteryStats()) {
    
    
            r.stats.stopLaunchedLocked();
        }
        //从ProcessRecord中移除Service记录
        r.app.stopService(r);
        //更新服务进程绑定的应用uids
        r.app.updateBoundClientUids();
        //允许绑定Service的应用程序管理白名单
        if (r.whitelistManager) {
    
    
            updateWhitelistManagerLocked(r.app);
        }
        if (r.app.thread != null) {
    
    
            //更新进程前台服务信息
            updateServiceForegroundLocked(r.app, false);
            try {
    
    
                //记录Service执行操作并设置超时回调
                //前台服务超时时间为20s,后台服务超时时间为200s
                bumpServiceExecutingLocked(r, false, "destroy");
                //添加到销毁中Service列表中
                mDestroyingServices.add(r);
                //标记正在销毁中
                r.destroying = true;
                //更新进程优先级
                mAm.updateOomAdjLocked(r.app, true,
                        OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE);
                //回到App进程,调度执行Service的stop操作
                r.app.thread.scheduleStopService(r);
            } catch (Exception e) {
    
    
                serviceProcessGoneLocked(r);
            }
        }
    }

    //清除连接
    if (r.bindings.size() > 0) {
    
    
        r.bindings.clear();
    }

    //对于主动停止的Service,不需要重启
    if (r.restarter instanceof ServiceRestarter) {
    
    
        ((ServiceRestarter)r.restarter).setService(null);
    }

    ... //记录

    //将此Service从正在后台启动服务列表和延迟启动服务列表中移除
    //如果正在后台启动服务列表中存在此服务的话,将之前设置为延迟启动的服务调度出来后台启动
    smap.ensureNotStartingBackgroundLocked(r);
}

这个方法主要做了以下几件事:

  1. 处理ClientSerivce的连接,进行断开连接以及解除绑定操作(具体等到后面分析unbindService时再说)
  2. 对于以前台服务形式启动,并且当前还尚未成为前台服务的Service,直接杀死App
  3. 各种重置,清理操作
  4. 关闭前台服务通知
  5. Service添加到销毁中服务列表,并调度执行停止操作,最终回调Service.onDestroy
  6. ServiceRestarter内的ServiceRecord变量设为null,避免其后续重启

我们重点看第5步,在这个方法中调用了ActivityThread$ApplicationThread.scheduleStopService去调度执行停止服务操作

//frameworks/base/core/java/android/app/ActivityThread.java
public final void scheduleStopService(IBinder token) {
    
    
    sendMessage(H.STOP_SERVICE, token);
}

同样的,也是通过Handler发送Message处理服务停止,这里最终调用的是ActivityThread.handleStopService方法

//frameworks/base/core/java/android/app/ActivityThread.java
private void handleStopService(IBinder token) {
    
    
    //从Service列表中取出并移除此服务
    Service s = mServices.remove(token);
    if (s != null) {
    
    
        try {
    
    
            //调用Service.onDestroy
            s.onDestroy();
            //解绑以及清理(解除对ServiceRecord的Binder远程对象的引用)
            s.detachAndCleanUp();
            //执行清理操作,具体来说就是断开其他客户端与Service的连接以及解除绑定
            Context context = s.getBaseContext();
            if (context instanceof ContextImpl) {
    
    
                final String who = s.getClassName();
                ((ContextImpl) context).scheduleFinalCleanup(who, "Service");
            }

            //确保其他异步任务执行完成
            QueuedWork.waitToFinish();

            try {
    
    
                //Service相关任务执行完成
                //这一步中会把之前的超时定时器取消
                ActivityManager.getService().serviceDoneExecuting(
                        token, SERVICE_DONE_EXECUTING_STOP, 0, 0);
            } catch (RemoteException e) {
    
    
                throw e.rethrowFromSystemServer();
            }
        } catch (Exception e) {
    
    
            if (!mInstrumentation.onException(s, e)) {
    
    
                throw new RuntimeException(
                        "Unable to stop service " + s
                        + ": " + e.toString(), e);
            }
        }
    }
}

可以看到,这里首先从mServices列表中取出并移除此服务,然后触发Service.onDestroy回调,之后还需要调用ContextImpl.scheduleFinalCleanup方法执行一些清理工作,这一部分的分析我们留到后面unbindService章节里再讲,这样,整个Service的停止流程就到此结束了

stopService

接下来我们来看一下调用方调用stopService停止服务的情况

//frameworks/base/core/java/android/app/ContextImpl.java
public boolean stopService(Intent service) {
    
    
    warnIfCallingFromSystemProcess();
    return stopServiceCommon(service, mUser);
}

private boolean stopServiceCommon(Intent service, UserHandle user) {
    
    
    try {
    
    
        //验证Intent有效性
        validateServiceIntent(service);
        //跨进程处理
        service.prepareToLeaveProcess(this);
        //调用AMS.stopService
        int res = ActivityManager.getService().stopService(
            mMainThread.getApplicationThread(), service,
            service.resolveTypeIfNeeded(getContentResolver()), user.getIdentifier());
        if (res < 0) {
    
    
            throw new SecurityException(
                    "Not allowed to stop service " + service);
        }
        return res != 0;
    } catch (RemoteException e) {
    
    
        throw e.rethrowFromSystemServer();
    }
}

这里基本上是直接调用AMS.stopService进入系统进程处理服务停止

//frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
public int stopService(IApplicationThread caller, Intent service,
        String resolvedType, int userId) {
    
    
    enforceNotIsolatedCaller("stopService");
    // Refuse possible leaked file descriptors
    if (service != null && service.hasFileDescriptors() == true) {
    
    
        throw new IllegalArgumentException("File descriptors passed in Intent");
    }

    synchronized(this) {
    
    
        //转交给ActiveServices处理
        return mServices.stopServiceLocked(caller, service, resolvedType, userId);
    }
}

//frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
int stopServiceLocked(IApplicationThread caller, Intent service,
        String resolvedType, int userId) {
    
    
    final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
    if (caller != null && callerApp == null) {
    
    
        throw new SecurityException(
                "Unable to find app for caller " + caller
                + " (pid=" + Binder.getCallingPid()
                + ") when stopping service " + service);
    }

    // If this service is active, make sure it is stopped.
    //查找相应的Service,其中入参createIfNeeded为false,所以如果从缓存中找不到ServiceRecord的话则会直接返回null
    ServiceLookupResult r = retrieveServiceLocked(service, null, resolvedType, null,
            Binder.getCallingPid(), Binder.getCallingUid(), userId, false, false, false, false);
    if (r != null) {
    
    
        if (r.record != null) {
    
    
            final long origId = Binder.clearCallingIdentity();
            try {
    
    
                //接着处理停止服务
                stopServiceLocked(r.record);
            } finally {
    
    
                Binder.restoreCallingIdentity(origId);
            }
            return 1;
        }
        return -1;
    }

    return 0;
}

private void stopServiceLocked(ServiceRecord service) {
    
    
    if (service.delayed) {
    
    
        // If service isn't actually running, but 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.
        service.delayedStop = true;
        return;
    }
    ... //统计信息记录

    //重置启动状态(重要,后文中会分析)
    service.startRequested = false;
    service.callStart = false;

    //和上文一样,停止Service
    bringDownServiceIfNeededLocked(service, false, false);
}

可以看到,这里和上文中分析的以stopSelf方式停止服务一样,先重置启动状态,然后调用bringDownServiceIfNeededLocked停止服务

unbindService

接下来的是通过bindService方法,并且flagBIND_AUTO_CREATE启动的Service,我们需要通过unbindService方法解除绑定,当最终没有任何flagBIND_AUTO_CREATE的客户端与Service绑定,这个Service就会被停止

//frameworks/base/core/java/android/app/ContextImpl.java
public void unbindService(ServiceConnection conn) {
    
    
    if (conn == null) {
    
    
        throw new IllegalArgumentException("connection is null");
    }
    if (mPackageInfo != null) {
    
    
        //将ServiceDispatcher的状态设置为forgotten,之后便不再会回调ServiceConnection任何方法
        IServiceConnection sd = mPackageInfo.forgetServiceDispatcher(
                getOuterContext(), conn);
        try {
    
    
            //调用AMS.unbindService方法
            ActivityManager.getService().unbindService(sd);
        } catch (RemoteException e) {
    
    
            throw e.rethrowFromSystemServer();
        }
    } else {
    
    
        throw new RuntimeException("Not supported in system context");
    }
}

这个方法中首先调用了LoadedApk.forgetServiceDispatcher方法

//frameworks/base/core/java/android/app/LoadedApk.java
public final IServiceConnection forgetServiceDispatcher(Context context,
        ServiceConnection c) {
    
    
    synchronized (mServices) {
    
    
        ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map
                = mServices.get(context);
        LoadedApk.ServiceDispatcher sd = null;
        if (map != null) {
    
    
            sd = map.get(c);
            if (sd != null) {
    
    
                //移除ServiceDispatcher
                map.remove(c);
                //清理连接并标记遗忘
                sd.doForget();
                if (map.size() == 0) {
    
    
                    mServices.remove(context);
                }
                ... //debug
                return sd.getIServiceConnection();
            }
        }
        ... //debug
        ... //异常
    }
}

ServiceDispatcher从缓存中移除并调用LoadedApk$ServiceDispatcher.doForget方法

//frameworks/base/core/java/android/app/LoadedApk.java
void doForget() {
    
    
    synchronized(this) {
    
    
        for (int i=0; i<mActiveConnections.size(); i++) {
    
    
            ServiceDispatcher.ConnectionInfo ci = mActiveConnections.valueAt(i);
            ci.binder.unlinkToDeath(ci.deathMonitor, 0);
        }
        mActiveConnections.clear();
        mForgotten = true;
    }
}

这里将所有连接的binder死亡回调移除,然后清除所有连接,再将mForgotten标记设为true

接着我们会走到AMS.unbindService方法中

//frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
public boolean unbindService(IServiceConnection connection) {
    
    
    synchronized (this) {
    
    
        return mServices.unbindServiceLocked(connection);
    }
}

同样的,将工作转交给ActiveServices

//frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
boolean unbindServiceLocked(IServiceConnection connection) {
    
    
    IBinder binder = connection.asBinder();
    ArrayList<ConnectionRecord> clist = mServiceConnections.get(binder);
    //找不到连接记录,直接返回
    if (clist == null) {
    
    
        return false;
    }

    final long origId = Binder.clearCallingIdentity();
    try {
    
    
        //遍历连接
        while (clist.size() > 0) {
    
    
            ConnectionRecord r = clist.get(0);
            //移除连接
            removeConnectionLocked(r, null, null);
            //removeConnectionLocked方法会将此ConnectionRecord从连接列表中移除
            //如果此ConnectionRecord仍然存在的话,是一个严重的错误,这里再移除一次
            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) {
    
    
                if (r.binding.service.app.whitelistManager) {
    
    
                    updateWhitelistManagerLocked(r.binding.service.app);
                }
                // 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);
                }
            }
        }

        //更新顶层应用进程优先级
        mAm.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE);

    } finally {
    
    
        Binder.restoreCallingIdentity(origId);
    }

    return true;
}

没看到什么特别重要的逻辑,看来重点应该在removeConnectionLocked这个方法中了

//frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
void removeConnectionLocked(ConnectionRecord c, ProcessRecord skipApp,
        ActivityServiceConnectionsHolder skipAct) {
    
    
    IBinder binder = c.conn.asBinder();
    AppBindRecord b = c.binding;
    ServiceRecord s = b.service;
    //这里的clist是ServiceRecord中的列表,和上一个方法中的clist不是一个对象
    ArrayList<ConnectionRecord> clist = s.getConnections().get(binder);
    //移除各种连接
    if (clist != null) {
    
    
        clist.remove(c);
        if (clist.size() == 0) {
    
    
            s.removeConnection(binder);
        }
    }
    b.connections.remove(c);
    c.stopAssociation();
    if (c.activity != null && c.activity != skipAct) {
    
    
        c.activity.removeConnection(c);
    }
    if (b.client != skipApp) {
    
    
        b.client.connections.remove(c);
        ... //各种flag的处理
        //更新是否有与Service建立连接的Activity
        if (s.app != null) {
    
    
            updateServiceClientActivitiesLocked(s.app, c, true);
        }
    }
    //将连接从mServiceConnections列表中移除
    //这个clist才是和上一个方法是同一个对象
    clist = mServiceConnections.get(binder);
    if (clist != null) {
    
    
        clist.remove(c);
        if (clist.size() == 0) {
    
    
            mServiceConnections.remove(binder);
        }
    }

    mAm.stopAssociationLocked(b.client.uid, b.client.processName, s.appInfo.uid,
            s.appInfo.longVersionCode, s.instanceName, s.processName);

    //如果调用方App没有其他连接和Service绑定
    //则将整个AppBindRecord移除
    if (b.connections.size() == 0) {
    
    
        b.intent.apps.remove(b.client);
    }

    if (!c.serviceDead) {
    
    
        //如果服务端进程存活并且没有其他连接绑定了,同时服务还处在绑定关系中(尚未回调过Service.onUnbind)
        if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
                && b.intent.hasBound) {
    
    
            try {
    
    
                bumpServiceExecutingLocked(s, false, "unbind");
                if (b.client != s.app && (c.flags&Context.BIND_WAIVE_PRIORITY) == 0
                        && s.app.setProcState <= ActivityManager.PROCESS_STATE_HEAVY_WEIGHT) {
    
    
                    // If this service's process is not already in the cached list,
                    // then update it in the LRU list here because this may be causing
                    // it to go down there and we want it to start out near the top.
                    mAm.updateLruProcessLocked(s.app, false, null);
                }
                mAm.updateOomAdjLocked(s.app, true,
                        OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE);
                //标记为未绑定
                b.intent.hasBound = false;
                // Assume the client doesn't want to know about a rebind;
                // we will deal with that later if it asks for one.
                b.intent.doRebind = false;
                //回到App进程,调度执行Service的unbind操作
                s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
            } catch (Exception e) {
    
    
                serviceProcessGoneLocked(s);
            }
        }

        // If unbound while waiting to start and there is no connection left in this service,
        // remove the pending service
        if (s.getConnections().isEmpty()) {
    
    
            mPendingServices.remove(s);
        }

        if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
    
    
            //是否有其他含有BIND_AUTO_CREATE标记的连接
            boolean hasAutoCreate = s.hasAutoCreateConnections();
            ... //记录
            bringDownServiceIfNeededLocked(s, true, hasAutoCreate);
        }
    }
}

这个方法主要做了以下几件事:

  1. 执行各种移除操作

  2. 如果目标服务在此次解绑后不再有任何其他连接与其绑定,则调度执行Serviceunbind操作

  3. 如果此次断开的连接的flag中包含BIND_AUTO_CREATE,则调用bringDownServiceIfNeededLocked尝试停止服务

2、3两点都很重要,我们首先看第2点,什么情况下会在这里调度执行Serviceunbind操作,前面描述的其实不是很准确,准确的来说应该是目标服务在同一个IntentBindRecord下,此次解绑后不再有任何其他连接与其绑定。那么什么叫同一个IntentBindRecord呢?这和我们启动服务传入的Intent有关,IntentBindRecord的第一次创建是在我们调用bindService后,走到ActiveServices.bindServiceLocked方法中,其中有一段代码调用了ServiceRecord.retrieveAppBindingLocked方法产生的

//frameworks/base/services/core/java/com/android/server/am/ServiceRecord.java
public AppBindRecord retrieveAppBindingLocked(Intent intent,
        ProcessRecord app) {
    
    
    Intent.FilterComparison filter = new Intent.FilterComparison(intent);
    IntentBindRecord i = bindings.get(filter);
    if (i == null) {
    
    
        i = new IntentBindRecord(this, filter);
        bindings.put(filter, i);
    }
    AppBindRecord a = i.apps.get(app);
    if (a != null) {
    
    
        return a;
    }
    a = new AppBindRecord(this, i, app);
    i.apps.put(app, a);
    return a;
}

在这个方法中,它将我们传入的Intent包装成了Intent.FilterComparison对象,然后尝试用它作为keyArrayMap``bindings中取获取IntentBindRecord,如果获取不到则会创建一个新的,那么是否是同一个IntentBindRecord的判断标准就是包装后的Intent.FilterComparison对象的HashCode是否相等,我们来看一下它的HashCode是怎样计算的:

//frameworks/base/core/java/android/content/Intent.java
public static final class FilterComparison {
    
    
    private final Intent mIntent;
    private final int mHashCode;

    public FilterComparison(Intent intent) {
    
    
        mIntent = intent;
        mHashCode = intent.filterHashCode();
    }
    ...
    @Override
    public int hashCode() {
    
    
        return mHashCode;
    }
}

public int filterHashCode() {
    
    
    int code = 0;
    if (mAction != null) {
    
    
        code += mAction.hashCode();
    }
    if (mData != null) {
    
    
        code += mData.hashCode();
    }
    if (mType != null) {
    
    
        code += mType.hashCode();
    }
    if (mIdentifier != null) {
    
    
        code += mIdentifier.hashCode();
    }
    if (mPackage != null) {
    
    
        code += mPackage.hashCode();
    }
    if (mComponent != null) {
    
    
        code += mComponent.hashCode();
    }
    if (mCategories != null) {
    
    
        code += mCategories.hashCode();
    }
    return code;
}

可以看到,只有以上参数全部相等,才会被视为同一个Intent,而我们通常使用Intent只会设置它的mComponent,所以在一般情况下ServiceonBindonUnbind也只会触发一次(在Service没有被销毁的情况下)

接着我们来看第3点,如果此次断开的连接的flag中包含BIND_AUTO_CREATE,首先会去查询是否有其他含有BIND_AUTO_CREATE标记的连接,然后以此作为参数调用bringDownServiceIfNeededLocked尝试停止服务

//frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
private final void bringDownServiceIfNeededLocked(ServiceRecord r, boolean knowConn,
        boolean hasConn) {
    
    
    //检查此服务是否还被需要
    if (isServiceNeededLocked(r, knowConn, hasConn)) {
    
    
        return;
    }

    // Are we in the process of launching?
    //不要停止正在启动中的Service
    if (mPendingServices.contains(r)) {
    
    
        return;
    }

    //继续停止服务
    bringDownServiceLocked(r);
}

private final boolean isServiceNeededLocked(ServiceRecord r, boolean knowConn,
        boolean hasConn) {
    
    
    // Are we still explicitly being asked to run?
    //Service之前是否通过startService启动过并且未stop
    if (r.startRequested) {
    
    
        return true;
    }

    // Is someone still bound to us keeping us running?
    //这里我们传入的是true
    //因为我们之前已经做了检查,知道了是否还有其他auto-create的连接
    if (!knowConn) {
    
    
        hasConn = r.hasAutoCreateConnections();
    }
    //如果还有其他auto-create的连接
    //则此服务还被需要
    if (hasConn) {
    
    
        return true;
    }

    return false;
}

可以看到,经过上述检查,如果发现此Service确实可以被停止了,则会调用bringDownServiceLocked方法停止服务

//frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
private final void bringDownServiceLocked(ServiceRecord r) {
    
    
    //断开所有连接
    ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections = r.getConnections();
    for (int conni = connections.size() - 1; conni >= 0; conni--) {
    
    
        ArrayList<ConnectionRecord> c = 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;
            cr.stopAssociation();
            //回调ServiceConnection各种方法
            //通知client服务断开连接以及死亡
            cr.conn.connected(r.name, null, true);
        }
    }

    // Tell the service that it has been unbound.
    //通知Service解除绑定
    if (r.app != null && r.app.thread != null) {
    
    
        boolean needOomAdj = false;
        //遍历所有连接,解除绑定
        for (int i = r.bindings.size() - 1; i >= 0; i--) {
    
    
            IntentBindRecord ibr = r.bindings.valueAt(i);
            //如果还处在绑定关系中(尚未回调过Service.onUnbind)
            if (ibr.hasBound) {
    
    
                try {
    
    
                    //记录Service执行操作并设置超时回调
                    //前台服务超时时间为20s,后台服务超时时间为200s
                    bumpServiceExecutingLocked(r, false, "bring down unbind");
                    needOomAdj = true;
                    //标记为未绑定
                    ibr.hasBound = false;
                    ibr.requested = false;
                    //回到App进程,调度执行Service的unbind操作
                    r.app.thread.scheduleUnbindService(r,
                            ibr.intent.getIntent());
                } catch (Exception e) {
    
    
                    needOomAdj = false;
                    serviceProcessGoneLocked(r);
                    break;
                }
            }
        }
        //更新服务端进程优先级
        if (needOomAdj) {
    
    
            mAm.updateOomAdjLocked(r.app, true,
                    OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE);
        }
    }
    ... //和上文相同
}

这个方法我们在前面分析stopSelf的时候说过了,这次我们只看和绑定服务有关的部分

首先断开所有连接,回调ServiceConnection各种方法,通知客户端服务断开连接以及死亡,这里需要注意的是,我们本次执行unbindService操作的连接已经在上一步中从ServiceRecord.connections列表中移除,所以并不会回调它的ServiceConnection的任何方法,这也是很多人对unbindService方法的误解(包括我自己),bindService方法在成功绑定服务后会回调ServiceConnection.onServiceConnected方法,但unbindService方法在成功解绑服务后并不会回调ServiceConnection.onServiceDisconnected以及任何其它方法,这些方法只会在Service被以其他方式停止(比如后面会分析的混合启动的服务如何停止)或者Service意外停止(比如服务端应用崩溃或被杀死)的情况才会被调用

所以这里处理的是断开其他的连接,我们假设一个场景,使用同一个Intent和两个不同的ServiceConnection,一个使用BIND_AUTO_CREATE标记,一个使用其他标记,先绑定BIND_AUTO_CREATE标记的Service,然后再绑定其他标记的Service,接着我们对BIND_AUTO_CREATE标记的Serivce调用unbindService解绑,此时就会走到这个方法中,ServiceRecord.connections列表中会存在那个使用其他标记的连接,然后其内部成员变量connconnected方法,这个conn是一个IServiceConnection类型,实际上的实现类为LoadedApk$ServiceDispatcher$InnerConnection,最终会调用到LoadedApk$ServiceDispatcher.doConnected方法

public void doConnected(ComponentName name, IBinder service, boolean dead) {
    
    
    ServiceDispatcher.ConnectionInfo old;
    ServiceDispatcher.ConnectionInfo info;

    synchronized (this) {
    
    
        //被标记为遗忘则不处理任何事情
        //调用unbindService就会将这个标志设为true
        if (mForgotten) {
    
    
            // We unbound before receiving the connection; ignore
            // any connection received.
            return;
        }
        old = mActiveConnections.get(name);
        //如果旧的连接信息中的IBinder对象和本次调用传入的IBinder对象是同一个对象
        if (old != null && old.binder == service) {
    
    
            // Huh, already have this one.  Oh well!
            return;
        }

        if (service != null) {
    
    
            // A new service is being connected... set it all up.
            //建立一个新的连接信息
            info = new ConnectionInfo();
            info.binder = service;
            info.deathMonitor = new DeathMonitor(name, service);
            try {
    
    
                //注册Binder死亡通知
                service.linkToDeath(info.deathMonitor, 0);
                //保存本次连接信息
                mActiveConnections.put(name, info);
            } catch (RemoteException e) {
    
    
                // This service was dead before we got it...  just
                // don't do anything with it.
                //服务已死亡,移除连接信息
                mActiveConnections.remove(name);
                return;
            }
        } else {
    
    
            // The named service is being disconnected... clean up.
            mActiveConnections.remove(name);
        }

        //移除Binder死亡通知
        if (old != null) {
    
    
            old.binder.unlinkToDeath(old.deathMonitor, 0);
        }
    }

    // If there was an old service, it is now disconnected.
    //回调ServiceConnection.onServiceDisconnected
    //通知client之前的连接已被断开
    if (old != null) {
    
    
        mConnection.onServiceDisconnected(name);
    }
    //如果Service死亡需要回调ServiceConnection.onBindingDied通知client服务死亡
    if (dead) {
    
    
        mConnection.onBindingDied(name);
    }
    // If there is a new viable service, it is now connected.
    if (service != null) {
    
    
        //回调ServiceConnection.onServiceConnected方法
        //告知client已建立连接
        mConnection.onServiceConnected(name, service);
    } else {
    
    
        // The binding machinery worked, but the remote returned null from onBind().
        //当Service.onBind方法返回null,或者Service停止时
        //回调ServiceConnection.onNullBinding方法
        mConnection.onNullBinding(name);
    }
}

这个方法其实我们在上一篇文章中已经说过了,不过在上一篇文章中我们关注的是Service绑定的部分,而这次我们关注的是解绑的部分

首先映入眼帘的就是对mForgotten变量的判断,它在客户端调用unbindService就会被设为true,然后便会直接返回,不再处理后续事项。当然,实际上执行完unbindService方法后,客户端与Service的连接会被移除,理论上应该也不会再走到这个方法里才对(这里我也感觉有点疑惑)

根据这段代码,我们能看出来Service停止后,对客户端的回调是什么:

  • Service.onBind方法的返回不为null时,此时会依次回调ServiceConnection.onServiceDisconnectedServiceConnection.onBindingDiedServiceConnection.onNullBinding方法

  • Service.onBind方法的返回为null时,此时会依次回调ServiceConnection.onBindingDiedServiceConnection.onNullBinding方法

大家也可以自己写写Demo来检验一下我说的是否正确

这一步处理完后,接下来要做的便是处理Service那边的解绑,遍历IntentBindRecord列表,调用ActivityThread$ApplicationThread.scheduleUnbindService去调度执行服务解绑操作,这里通过Handler最终调用的是ActivityThread.handleUnbindService方法

//frameworks/base/core/java/android/app/ActivityThread.java
private void handleUnbindService(BindServiceData data) {
    
    
    Service s = mServices.get(data.token);
    if (s != null) {
    
    
        try {
    
    
            data.intent.setExtrasClassLoader(s.getClassLoader());
            data.intent.prepareToEnterProcess();
            //回调Service.onUnbind方法,如果返回值为true
            //当再次建立连接时,服务会回调Service.onRebind方法
            boolean doRebind = s.onUnbind(data.intent);
            try {
    
    
                if (doRebind) {
    
    
                    ActivityManager.getService().unbindFinished(
                            data.token, data.intent, doRebind);
                } else {
    
    
                    ActivityManager.getService().serviceDoneExecuting(
                            data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
                }
            } catch (RemoteException ex) {
    
    
                throw ex.rethrowFromSystemServer();
            }
        } catch (Exception e) {
    
    
            if (!mInstrumentation.onException(s, e)) {
    
    
                throw new RuntimeException(
                        "Unable to unbind to service " + s
                        + " with " + data.intent + ": " + e.toString(), e);
            }
        }
    }
}

可以看到,这里回调了Service.onUnbind方法,它的返回值表示当Service后面再与其他客户端建立连接时,是否需要回调Service.onRebind方法,但是这有一个前提,那就是Service中途没有被停止,具体原因以及rebind流程我们稍后再分析

到了这一步,解绑就完成了,接下来和之前在stopSelf章节里分析的后续流程就一样了,最终调用ActivityThread.handleStopService方法停止服务,还记得我们之前分析在这个方法中触发完Service.onDestroy回调,之后还需要调用ContextImpl.scheduleFinalCleanup方法吗?现在我们就来看看这个方法又做了什么事情

//frameworks/base/core/java/android/app/ContextImpl.java
final void scheduleFinalCleanup(String who, String what) {
    
    
    mMainThread.scheduleContextCleanup(this, who, what);
}

这里的mMainThread就是应用的ActivityThread

//frameworks/base/core/java/android/app/ActivityThread.java
final void scheduleContextCleanup(ContextImpl context, String who,
        String what) {
    
    
    ContextCleanupInfo cci = new ContextCleanupInfo();
    cci.context = context;
    cci.who = who;
    cci.what = what;
    sendMessage(H.CLEAN_UP_CONTEXT, cci);
}

还是老样子通过Handler发消息,最终调用的是ContextImpl.performFinalCleanup方法

//frameworks/base/core/java/android/app/ContextImpl.java
final void performFinalCleanup(String who, String what) {
    
    
    mPackageInfo.removeContextRegistrations(getOuterContext(), who, what);
}

然后调用LoadedApk.removeContextRegistrations方法执行清理操作

//frameworks/base/core/java/android/app/LoadedApk.java
public void removeContextRegistrations(Context context,
        String who, String what) {
    
    
    ... //清理广播接收器

    synchronized (mServices) {
    
    
        ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> smap =
                mServices.remove(context);
        if (smap != null) {
    
    
            for (int i = 0; i < smap.size(); i++) {
    
    
                LoadedApk.ServiceDispatcher sd = smap.valueAt(i);
                ... //报告ServiceConnection泄露
                try {
    
    
                    ActivityManager.getService().unbindService(
                            sd.getIServiceConnection());
                } catch (RemoteException e) {
    
    
                    throw e.rethrowFromSystemServer();
                }
                sd.doForget();
            }
        }
        mUnboundServices.remove(context);
    }
}

可能看到这里,有很多小伙伴会有疑问,为什么之前已经清理过了,这里还要再进行清理、这里为什么会有ServiceConnection泄露、这里为什么还要再次unbindService?那我们需要注意了,这里被调用的对象到底是谁?其实是ServiceContext,假设我们在Serivce里调用bindService又绑定了一个其他Service,那这个Service被销毁后,它和另一个Service的连接怎么办?是不是就产生了泄露?为了防止这种情况,所以我们需要在Service销毁时调用一下这个方法解除它与其他Service的绑定

而且这个方法不仅会在这里被调用到哦,在我们之前分析过的 Android源码分析 - Activity销毁流程 中,也存在它的身影,当Activity被销毁,走到handleDestroyActivity方法时,会调用到我们ContextImpl.scheduleFinalCleanup方法,进行广播接收器的清理以及服务的解绑

至此,Service的主动停止流程我们都分析完了,还有一些细枝末节的事情可以说一说

rebind流程

之前我们说过,rebind的前提是Service中途没有被停止,为什么呢?带着疑问,我们来看之前没有分析的,当Service.onUnbind方法返回值为true时,会调用的AMS.unbindFinished方法

//frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
    
    
    // Refuse possible leaked file descriptors
    if (intent != null && intent.hasFileDescriptors() == true) {
    
    
        throw new IllegalArgumentException("File descriptors passed in Intent");
    }

    synchronized(this) {
    
    
        mServices.unbindFinishedLocked((ServiceRecord)token, intent, doRebind);
    }
}

还是转交给ActiveServices去实现

//frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
void unbindFinishedLocked(ServiceRecord r, Intent intent, boolean doRebind) {
    
    
    final long origId = Binder.clearCallingIdentity();
    try {
    
    
        if (r != null) {
    
    
            Intent.FilterComparison filter
                    = new Intent.FilterComparison(intent);
            IntentBindRecord b = r.bindings.get(filter);

            boolean inDestroying = mDestroyingServices.contains(r);
            if (b != null) {
    
    
                //服务unbind的前提就是IntentBindRecord.apps.size == 0
                if (b.apps.size() > 0 && !inDestroying) {
    
    
                    ...
                } else {
    
    
                    // Note to tell the service the next time there is
                    // a new client.
                    //将doRebind标记置为true,下一次再次建立连接时
                    //服务会回调Service.onRebind方法
                    b.doRebind = true;
                }
            }

            serviceDoneExecutingLocked(r, inDestroying, false);
        }
    } finally {
    
    
        Binder.restoreCallingIdentity(origId);
    }
}

根据我们之前的分析,我们知道,回调Service.onUnbind的前提就是这个Service没有任何连接与其绑定了,即IntentBindRecord.apps.size == 0,在这个case下,这个方法会将IntentBindRecorddoRebind变量置为true

此时让我们再回顾一下上一篇文章 Android源码分析 - Service启动流程 中分析的bindService流程,在ActiveServices.bindServiceLocked方法中有这么一段代码

//frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
        String resolvedType, final IServiceConnection connection, int flags,
        String instanceName, String callingPackage, final int userId)
        throws TransactionTooLargeException {
    
    
    ...
    if (s.app != null && b.intent.received) {
    
    
        // Service is already running, so we can immediately
        // publish the connection.
        //如果服务之前就已经在运行,即Service.onBind方法已经被执行,返回的IBinder对象也已经被保存
        //调用LoadedApk$ServiceDispatcher$InnerConnection.connected方法
        //回调ServiceConnection.onServiceConnected方法
        c.conn.connected(s.name, b.intent.binder, false);

        // If this is the first app connected back to this binding,
        // and the service had previously asked to be told when
        // rebound, then do so.
        //当服务解绑,调用到Service.onUnbind方法时返回true,此时doRebind变量就会被赋值为true
        //此时,当再次建立连接时,服务会回调Service.onRebind方法
        if (b.intent.apps.size() == 1 && b.intent.doRebind) {
    
    
            requestServiceBindingLocked(s, b.intent, callerFg, true);
        }
    } else if (!b.intent.requested) {
    
    
        //如果服务是因这次绑定而创建的
        //请求执行Service.onBind方法,获取返回的IBinder对象
        //发布Service,回调ServiceConnection.onServiceConnected方法
        requestServiceBindingLocked(s, b.intent, callerFg, false);
    }
    ...
}

如果Service被停止了,那么它相应的ServiceRecord会从缓存mServicesByInstanceNamemServicesByIntent中移除,那么等到重新启动Service时会新建出一个ServiceRecord,此时里面的变量全部被初始化,b.intent.received == falseb.intent.requested == falseb.intent.doRebind == false,在这种情况下,调用requestServiceBindingLocked方法的最后一个入参rebindfalse,就会直接回调Service.onBind方法,而不会回调Service.onRebind方法

如果Service没有被停止,且之前有被绑定过,那么b.intent.received == true,代表IBinder对象已获取到,此时如果之前的Service.onUnbind回调返回值为true,那么这里的b.intent.doRebind也为true,再加上如果这是Service断开所有连接后建立的第一次连接,即b.intent.apps.size() == 1,那么此时调用的requestServiceBindingLocked方法的最后一个入参rebindtrue,就会直接回调Service.onRebind方法,而不会回调Service.onBind方法

混合启动的Service该如何停止

单一启动方式的Service的停止很简单,那么混合启动的Service该如何停止呢?

何为混合启动?指的是通过startService方式启动Service并且以BIND_AUTO_CREATE标志调用bindService方法绑定Service,两者不分先后

在上面的分析中,我们注意到,不管用哪种方式停止服务,最后都会走到bringDownServiceIfNeededLocked方法中,在这个方法里又会调用isServiceNeededLocked判断是否Service是否被需要,那被需要的条件是什么呢?Service.startRequestedtrue,并且没有标志为BIND_AUTO_CREATE的连接绑定,那么,只要不符合这两个条件,服务自然就可以被停止了

没有标志为BIND_AUTO_CREATE的连接绑定这个简单,只需要把标记为BIND_AUTO_CREATE的连接全部解绑了就好,那么怎么让Service.startRequestedfalse呢?我们回顾一下之前对stopSelfstopService的分析,在他们调用bringDownServiceIfNeededLocked方法之前,都会先将Service.startRequested设置为false,所以答案就很明显了:只要unbindService掉所有BIND_AUTO_CREATE的标志的连接,然后stopService就能停止掉混合启动的服务,当然你也可以先stopService,再unbindService掉所有BIND_AUTO_CREATE的标志的连接

小测验

经过以上一系列的分析,我给大家出几个小问题:

  1. 先通过startService启动服务,然后再用BIND_AUTO_CREATE标志bindService(连接1),此时,Service的生命周期是怎样的?ServiceConnection会回调哪些方法?

  2. 在上一题的基础上,再使用一个非BIND_AUTO_CREATE标志bindService(连接2),此时,Service的生命周期是怎样的?ServiceConnection会回调哪些方法?

  3. 此时,使用unbindService解绑连接1,会发生什么?ServiceConnection会回调哪些方法?

  4. 此时,使用unbindService解绑连接2,会发生什么?ServiceConnection会回调哪些方法?

  5. 接着,再使用连接1bindService,会发生什么?ServiceConnection会回调哪些方法?

  6. 然后,调用stopService停止服务,服务真的会被停止吗?Service的生命周期是怎样的?连接1的ServiceConnection会回调哪些方法?

  7. 紧接着,再使用连接2bindService,会发生什么?连接2的ServiceConnection会回调哪些方法?

  8. 最后,调用unbindService解绑连接1,会发生什么?Service的生命周期是怎样的?ServiceConnection会回调哪些方法?

请大家思考片刻,可以去回顾之前的Service启动分析以及停止流程分析,如果以上问题能全部回答正确,证明你对Service已经有了一个很深刻的理解,接下来揭晓答案:

  1. 生命周期:onCreate -> onStartCommand -> onBind,如果onBind的返回值不为nullServiceConnection会回调onServiceConnected方法,如果onBind的返回值为nullServiceConnection会回调onNullBinding方法

  2. 生命周期不会发生变化,如果onBind的返回值不为nullServiceConnection会回调onServiceConnected方法,如果onBind的返回值为nullServiceConnection会回调onNullBinding方法

  3. 生命周期不会发生变化,ServiceConnection不会回调任何方法

  4. 生命周期:onUnbindServiceConnection不会回调任何方法

  5. 如果之前onUnbind的返回值为true,则生命周期为:onRebind,否则生命周期不会发生变化,如果之前onBind的返回值不为nullServiceConnection会回调onServiceConnected方法,如果之前onBind的返回值为nullServiceConnection会回调onNullBinding方法

  6. 不会真的被停止,生命周期不会发生变化,ServiceConnection不会回调任何方法

  7. 生命周期不会发生变化,如果之前onBind的返回值不为nullServiceConnection会回调onServiceConnected方法,如果之前onBind的返回值为nullServiceConnection会回调onNullBinding方法

  8. 服务会被停止,生命周期:onUnbind -> onDestroy,连接1的ServiceConnection不会回调任何方法,如果之前onBind的返回值不为null,连接2的ServiceConnection会回调onServiceDisconnectedonBindingDied以及onNullBinding方法,如果之前onBind的返回值为null,连接2的ServiceConnection会回调onBindingDied以及onNullBinding方法

被动停止

Service除了主动停止,还会因为各种情况导致被动停止

用户手动从最近任务移除Task

注:由于各家系统对进程或任务调度策略不同,所以这里的Task移除逻辑和Service停止逻辑可能会有些许不同,我们还是以原生Android为准分析

不管用户是从最近任务划走了一个Task,还是点击了全部清除,最终都会走到ActivityStackSupervisor.removeTaskById方法

//frameworks/base/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
boolean removeTaskById(int taskId, boolean killProcess, boolean removeFromRecents,
        String reason) {
    
    
    //通过id查询Task
    final Task task =
            mRootWindowContainer.anyTaskForId(taskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
    if (task != null) {
    
    
        removeTask(task, killProcess, removeFromRecents, reason);
        return true;
    }
    return false;
}

这里的入参,killProcesstrue,如果是移除单一Task,那么removeFromRecentstrue,如果是清除全部Task,那么removeFromRecentsfalse

先通过id,使用RootWindowContainer查询相应的Task,然后再调用removeTask方法继续移除Task

//frameworks/base/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
void removeTask(Task task, boolean killProcess, boolean removeFromRecents, String reason) {
    
    
    //如果Task正在清理中则直接返回
    if (task.mInRemoveTask) {
    
    
        // Prevent recursion.
        return;
    }
    //标记Task正在清理中
    task.mInRemoveTask = true;
    try {
    
    
        //销毁此Task下所有Activity
        task.performClearTask(reason);
        //清理Task
        cleanUpRemovedTaskLocked(task, killProcess, removeFromRecents);
        //关闭屏幕固定
        mService.getLockTaskController().clearLockedTask(task);
        //通知任务栈发生变化
        mService.getTaskChangeNotificationController().notifyTaskStackChanged();
        //启动任务持久化程序,将任何挂起的任务写入磁盘
        if (task.isPersistable) {
    
    
            mService.notifyTaskPersisterLocked(null, true);
        }
    } finally {
    
    
        //取消标记
        task.mInRemoveTask = false;
    }
}

这个方法最重要的有两个部分,一个是销毁此Task下所有Activity,对于我们本次而言不需要关注,另一个是调用cleanUpRemovedTaskLocked继续清理Task

//frameworks/base/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
void cleanUpRemovedTaskLocked(Task task, boolean killProcess, boolean removeFromRecents) {
    
    
    //从最近任务列表中移除
    //对于清除全部Task而言,之前在RecentTasks中已经进行过移除操作了
    //所以传入的removeFromRecents为false
    if (removeFromRecents) {
    
    
        mRecentTasks.remove(task);
    }
    ComponentName component = task.getBaseIntent().getComponent();
    if (component == null) {
    
    
        return;
    }

    // Find any running services associated with this app and stop if needed.
    //清理和此Task有关联的服务
    final Message msg = PooledLambda.obtainMessage(ActivityManagerInternal::cleanUpServices,
            mService.mAmInternal, task.mUserId, component, new Intent(task.getBaseIntent()));
    mService.mH.sendMessage(msg);

    //如果不需要杀死进程,到这里就为止了
    if (!killProcess) {
    
    
        return;
    }

    // Determine if the process(es) for this task should be killed.
    final String pkg = component.getPackageName();
    ArrayList<Object> procsToKill = new ArrayList<>();
    ArrayMap<String, SparseArray<WindowProcessController>> pmap = 
            mService.mProcessNames.getMap();
    //遍历App进程,确定要杀死的进程
    for (int i = 0; i < pmap.size(); i++) {
    
    
        SparseArray<WindowProcessController> uids = pmap.valueAt(i);
        for (int j = 0; j < uids.size(); j++) {
    
    
            WindowProcessController proc = uids.valueAt(j);
            //不要杀死其他用户下的进程
            if (proc.mUserId != task.mUserId) {
    
    
                // Don't kill process for a different user.
                continue;
            }
            //不要杀死首页进程
            //HomeProcess指的是含有分类为android.intent.category.HOME的进程
            //也就是能成为首页Launcher的进程
            if (proc == mService.mHomeProcess) {
    
    
                // Don't kill the home process along with tasks from the same package.
                continue;
            }
            //不要杀死和这个Task无关的进程
            if (!proc.mPkgList.contains(pkg)) {
    
    
                // Don't kill process that is not associated with this task.
                continue;
            }

            //如果这个进程有Activity在不同的Task里,并且这个Task也在最近任务里
            //或者有Activity还没有被停止,则不要杀死进程
            if (!proc.shouldKillProcessForRemovedTask(task)) {
    
    
                // Don't kill process(es) that has an activity in a different task that is also
                // in recents, or has an activity not stopped.
                return;
            }

            //有前台服务的话不要杀死进程
            if (proc.hasForegroundServices()) {
    
    
                // Don't kill process(es) with foreground service.
                return;
            }

            // Add process to kill list.
            procsToKill.add(proc);
        }
    }

    // Kill the running processes. Post on handle since we don't want to hold the service lock
    // while calling into AM.
    //杀死进程
    final Message m = PooledLambda.obtainMessage(
            ActivityManagerInternal::killProcessesForRemovedTask, mService.mAmInternal,
            procsToKill);
    mService.mH.sendMessage(m);
}

这个方法主要做两件事,一是清理和此Task有关联的服务,二是杀死应该杀死的进程

清理服务这一步用到了池化技术,这里大家不用管,就当做调用了mService.mAmInternal.cleanUpServices即可,这里的mService.mAmInternalAMS里的一个内部类LocalService

//frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
public void cleanUpServices(int userId, ComponentName component, Intent baseIntent) {
    
    
    synchronized(ActivityManagerService.this) {
    
    
        mServices.cleanUpServices(userId, component, baseIntent);
    }
}

同样,关于Service的工作都转交给ActiveServices

//frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
void cleanUpServices(int userId, ComponentName component, Intent baseIntent) {
    
    
    ArrayList<ServiceRecord> services = new ArrayList<>();
    //获得此用户下所有的活动Service
    ArrayMap<ComponentName, ServiceRecord> alls = getServicesLocked(userId);
    //筛选出此Task下的所有活动Service
    for (int i = alls.size() - 1; i >= 0; i--) {
    
    
        ServiceRecord sr = alls.valueAt(i);
        if (sr.packageName.equals(component.getPackageName())) {
    
    
            services.add(sr);
        }
    }

    // Take care of any running services associated with the app.
    for (int i = services.size() - 1; i >= 0; i--) {
    
    
        ServiceRecord sr = services.get(i);
        if (sr.startRequested) {
    
    
            if ((sr.serviceInfo.flags&ServiceInfo.FLAG_STOP_WITH_TASK) != 0) {
    
    
                //如果在manifest里设置了stopWithTask,那么会直接停止Service
                stopServiceLocked(sr);
            } else {
    
    
                //如果没有设置stopWithTask的话,则会回调Service.onTaskRemoved方法
                sr.pendingStarts.add(new ServiceRecord.StartItem(sr, true,
                        sr.getLastStartId(), baseIntent, null, 0));
                if (sr.app != null && sr.app.thread != null) {
    
    
                    // We always run in the foreground, since this is called as
                    // part of the "remove task" UI operation.
                    try {
    
    
                        sendServiceArgsLocked(sr, true, false);
                    } catch (TransactionTooLargeException e) {
    
    
                        // Ignore, keep going.
                    }
                }
            }
        }
    }
}

首先要获取到所有需要清理的Service记录,然后再对它们进行处理

对于在manifest文件里设置了stopWithTask标识的Service,直接调用stopServiceLocked方法停止服务,而对于没有这个标识的Service,则是增加一个启动项,接着调用sendServiceArgsLocked处理这个启动项

我们观察这个启动项的构建,第二个参数为true,我们可以去这个类的构造方法那里看到,第二个参数的名字为_taskRemoved,意思很明显了,然后根据我们在上一篇文章 Android源码分析 - Service启动流程 中分析的sendServiceArgsLocked方法可以知道,它最终会走到ActivityThread.handleServiceArgs方法中

//frameworks/base/core/java/android/app/ActivityThread.java
private void handleServiceArgs(ServiceArgsData data) {
    
    
    ...
    int res;
    if (!data.taskRemoved) {
    
    
        //正常情况调用
        res = s.onStartCommand(data.args, data.flags, data.startId);
    } else {
    
    
        //用户关闭Task栈时调用
        s.onTaskRemoved(data.args);
        res = Service.START_TASK_REMOVED_COMPLETE;
    }
    ...
}

可以发现,当taskRemoved变量为true时,会回调Service.onTaskRemoved方法

我们接着回到cleanUpRemovedTaskLocked方法中,当它清理完服务后,便会尝试杀死进程,这里面其他的判断条件我们都不用管,我们只需要关心其中的一段,有前台服务的话不要杀死进程

以上是我根据AOSP源码分析得出的结果,在模拟器上也验证通过,但在我的小米MIX4上表现却完全不是这样,大家开发时还是要以实际为准

内存不足

当内存不足时,系统会通过OOM KillerLow Memory Killer等手段杀死各种进程,如果被杀死的进程里有Service正在运行,那自然也会被停止

重建

Service所在进程被杀死后,根据Service.onStartCommand的返回值,系统会决定是否重建,怎么重建。我们先把其可能的返回值以及产生的结果先列出来:

  • START_STICKY_COMPATIBILITYtargetSdkVersion < 5 (Android 2.0) 的App默认会返回这个,Service被杀后会被重建,但onStartCommand方法不会被执行
  • START_STICKYtargetSdkVersion >= 5 (Android 2.0) 的App默认会返回这个,Service被杀后会被重建,onStartCommand方法也会被执行,但此时onStartCommand方法的第一个参数Intentnull
  • START_NOT_STICKYService被杀后不会被重建
  • START_REDELIVER_INTENTService被杀后会被重建,onStartCommand方法也会被执行,此时onStartCommand方法的第一个参数IntentService被杀死前最后一次调用onStartCommand方法时传递的Intent

对于其返回值我们需要先了解一下是怎么处理的,这需要回顾一下上一篇文章分析的handleServiceArgs方法了

//frameworks/base/core/java/android/app/ActivityThread.java
private void handleServiceArgs(ServiceArgsData data) {
    
    
    Service s = mServices.get(data.token);
    if (s != null) {
    
    
        try {
    
    
            ...
            int res;
            if (!data.taskRemoved) {
    
    
                //正常情况调用
                res = s.onStartCommand(data.args, data.flags, data.startId);
            } else {
    
    
                //用户关闭Task栈时调用
                s.onTaskRemoved(data.args);
                res = Service.START_TASK_REMOVED_COMPLETE;
            }

            //确保其他异步任务执行完成
            QueuedWork.waitToFinish();

            try {
    
    
                //Service相关任务执行完成
                //这一步会根据onStartCommand的返回值,调整Service死亡重建策略
                //同时会把之前的启动超时定时器取消
                ActivityManager.getService().serviceDoneExecuting(
                        data.token, SERVICE_DONE_EXECUTING_START, data.startId, res);
            } catch (RemoteException e) {
    
    
                throw e.rethrowFromSystemServer();
            }
        } catch (Exception e) {
    
    
            if (!mInstrumentation.onException(s, e)) {
    
    
                throw new RuntimeException(
                        "Unable to start service " + s
                        + " with " + data.args + ": " + e.toString(), e);
            }
        }
    }
}

可以看到,这里从Service.onStartCommand得到返回值后以其作为参数调用了AMS.serviceDoneExecuting方法

//frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
    
    
    synchronized(this) {
    
    
        ...
        mServices.serviceDoneExecutingLocked((ServiceRecord)token, type, startId, res);
    }
}

转交给了ActiveServices.serviceDoneExecutingLocked方法

//frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
void serviceDoneExecutingLocked(ServiceRecord r, int type, int startId, int res) {
    
    
    boolean inDestroying = mDestroyingServices.contains(r);
    if (r != null) {
    
    
        if (type == ActivityThread.SERVICE_DONE_EXECUTING_START) {
    
    
            // This is a call from a service start...  take care of
            // book-keeping.
            r.callStart = true;
            switch (res) {
    
    
                case Service.START_STICKY_COMPATIBILITY:
                case Service.START_STICKY: {
    
    
                    // We are done with the associated start arguments.
                    r.findDeliveredStart(startId, false, true);
                    // Don't stop if killed.
                    r.stopIfKilled = false;
                    break;
                }
                case Service.START_NOT_STICKY: {
    
    
                    // We are done with the associated start arguments.
                    r.findDeliveredStart(startId, false, true);
                    if (r.getLastStartId() == startId) {
    
    
                        // There is no more work, and this service
                        // doesn't want to hang around if killed.
                        r.stopIfKilled = true;
                    }
                    break;
                }
                case Service.START_REDELIVER_INTENT: {
    
    
                    // We'll keep this item until they explicitly
                    // call stop for it, but keep track of the fact
                    // that it was delivered.
                    ServiceRecord.StartItem si = r.findDeliveredStart(startId, false, false);
                    if (si != null) {
    
    
                        si.deliveryCount = 0;
                        si.doneExecutingCount++;
                        // Don't stop if killed.
                        r.stopIfKilled = true;
                    }
                    break;
                }
                case Service.START_TASK_REMOVED_COMPLETE: {
    
    
                    // Special processing for onTaskRemoved().  Don't
                    // impact normal onStartCommand() processing.
                    r.findDeliveredStart(startId, true, true);
                    break;
                }
                default:
                    throw new IllegalArgumentException(
                            "Unknown service start result: " + res);
            }
            if (res == Service.START_STICKY_COMPATIBILITY) {
    
    
                r.callStart = false;
            }
        } else if (type == ActivityThread.SERVICE_DONE_EXECUTING_STOP) {
    
    
            ...
        }
        ...
    } else {
    
     ... }
}

我们就只看对Service.onStartCommand的返回值进行处理的部分

首先,不管返回值是什么,都会调用ServiceRecord.findDeliveredStart方法,只不过入参不同

//frameworks/base/services/core/java/com/android/server/am/ServiceRecord.java
public StartItem findDeliveredStart(int id, boolean taskRemoved, boolean remove) {
    
    
    final int N = deliveredStarts.size();
    for (int i=0; i<N; i++) {
    
    
        StartItem si = deliveredStarts.get(i);
        if (si.id == id && si.taskRemoved == taskRemoved) {
    
    
            if (remove) deliveredStarts.remove(i);
            return si;
        }
    }

    return null;
}

前两个参数,不管返回值是什么,传进来的都是一样的,而第三个参数remove就不同了,当返回值为START_REDELIVER_INTENT的时候,它为false,其他情况都为true,意味着要删除这个已分发的启动项,START_REDELIVER_INTENT由于需要保留最后一次调用onStartCommand时的Intent,所以它不应该被删除

接着我们回到serviceDoneExecutingLocked方法,可以发现,START_STICKYSTART_STICKY_COMPATIBILITY情况下的ServiceRecord.stopIfKilled被置为了false,其他则被置为了true,这和我们之前对结果的描述不同啊?不是说好了返回START_REDELIVER_INTENT也会重启吗?这是因为START_REDELIVER_INTENT比较特殊,它的重启不需要看stopIfKilled这个标志位,这个等到我们后面分析到怎么判断是否应该停止服务时就知道了

以上的内容我们先记下来,会在后面的重启流程中发挥作用

然后我们来看进程死亡后会发生什么,我们曾在之前的文章 Android源码分析 - Activity启动流程(中) 中提到过,当App启动时,AMS会为其注册一个App进程死亡回调AppDeathRecipient,当App进程死亡后便会回调其binderDied方法

//frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
private final class AppDeathRecipient implements IBinder.DeathRecipient {
    
    
    final ProcessRecord mApp;
    final int mPid;
    final IApplicationThread mAppThread;

    AppDeathRecipient(ProcessRecord app, int pid,
            IApplicationThread thread) {
    
    
        mApp = app;
        mPid = pid;
        mAppThread = thread;
    }

    @Override
    public void binderDied() {
    
    
        synchronized(ActivityManagerService.this) {
    
    
            appDiedLocked(mApp, mPid, mAppThread, true, null);
        }
    }
}

接着便会调用appDiedLocked方法处理进程死亡

//frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
final void appDiedLocked(ProcessRecord app, int pid, IApplicationThread thread,
        boolean fromBinderDied, String reason) {
    
    
    // First check if this ProcessRecord is actually active for the pid.
    //检查pid所属ProcessRecord是否与传入ProcessRecord相符
    synchronized (mPidsSelfLocked) {
    
    
        ProcessRecord curProc = mPidsSelfLocked.get(pid);
        if (curProc != app) {
    
    
            return;
        }
    }

    ... //记录电池统计信息

    //如果App进程尚未死亡的话,杀死进程
    if (!app.killed) {
    
    
        if (!fromBinderDied) {
    
    
            killProcessQuiet(pid);
            mProcessList.noteAppKill(app, ApplicationExitInfo.REASON_OTHER,
                    ApplicationExitInfo.SUBREASON_UNKNOWN, reason);
        }
        ProcessList.killProcessGroup(app.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()) {
    
    
        //一般情况下非自动化测试,先置为true
        boolean doLowMem = app.getActiveInstrumentation() == null;
        boolean doOomAdj = doLowMem;
        if (!app.killedByAm) {
    
     //不通过AMS杀死的进程,一般就是被 Low Memory Killer (LMK) 杀死的
            ... //报告信息
            //被LMK杀死,说明系统内存不足
            mAllowLowerMemLevel = true;
        } else {
    
     //通过AMS杀死的进程
            // Note that we always want to do oom adj to update our state with the
            // new number of procs.
            mAllowLowerMemLevel = false;
            //正常情况下非内存不足
            doLowMem = false;
        }
        ... //事件记录
        //继续处理App进程死亡
        handleAppDiedLocked(app, false, true);

        //调整进程优先级
        if (doOomAdj) {
    
    
            updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_PROCESS_END);
        }
        //当因为内存不足而杀死App进程时
        //调用App层各处的的onLowMemory方法,释放内存
        if (doLowMem) {
    
    
            doLowMemReportIfNeededLocked(app);
        }
    } else if (app.pid != pid) {
    
     //新进程已启动
        // A new process has already been started.
        ... //报告记录信息
    }
    ...
}

这里的其他代码我们都不用关心,直接看handleAppDiedLocked方法继续处理App进程死亡

//frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
final void handleAppDiedLocked(ProcessRecord app,
        boolean restarting, boolean allowRestart) {
    
    
    ...
    //清理进程的主要方法
    boolean kept = cleanUpApplicationRecordLocked(app, restarting, allowRestart, -1,
            false /*replacingPid*/);
    ...
}

final boolean cleanUpApplicationRecordLocked(ProcessRecord app,
        boolean restarting, boolean allowRestart, int index, boolean replacingPid) {
    
    
    ...
    mServices.killServicesLocked(app, allowRestart);
    ...
}

可以看到,这里调用了ActiveServices.killServicesLocked方法停止还在运行中的服务

final void killServicesLocked(ProcessRecord app, boolean allowRestart) {
    
    
    // Clean up any connections this application has to other services.
    //清理所有连接
    for (int i = app.connections.size() - 1; i >= 0; i--) {
    
    
        ConnectionRecord r = app.connections.valueAt(i);
        removeConnectionLocked(r, app, null);
    }
    updateServiceConnectionActivitiesLocked(app);
    app.connections.clear();

    app.whitelistManager = false;

    // Clear app state from services.
    //遍历所有正在运行中的服务
    for (int i = app.numberOfRunningServices() - 1; i >= 0; i--) {
    
    
        ServiceRecord sr = app.getRunningServiceAt(i);
        synchronized (sr.stats.getBatteryStats()) {
    
    
            sr.stats.stopLaunchedLocked();
        }
        if (sr.app != app && sr.app != null && !sr.app.isPersistent()) {
    
    
            //记录服务已停止
            sr.app.stopService(sr);
            //更新绑定的客户端uids
            sr.app.updateBoundClientUids();
        }
        sr.setProcess(null);
        sr.isolatedProc = null;
        sr.executeNesting = 0;
        sr.forceClearTracker();
        if (mDestroyingServices.remove(sr)) {
    
    
            if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "killServices remove destroying " + sr);
        }

        final int numClients = sr.bindings.size();
        for (int bindingi=numClients-1; bindingi>=0; bindingi--) {
    
    
            IntentBindRecord b = sr.bindings.valueAt(bindingi);
            //释放对服务Binder的引用
            b.binder = null;
            //重置
            b.requested = b.received = b.hasBound = false;
            // If this binding is coming from a cached process and is asking to keep
            // the service created, then we'll kill the cached process as well -- we
            // don't want to be thrashing around restarting processes that are only
            // there to be cached.
            ... //遍历客户端进程(实际上没做任何事)
        }
    }

    ServiceMap smap = getServiceMapLocked(app.userId);

    // Now do remaining service cleanup.
    for (int i = app.numberOfRunningServices() - 1; i >= 0; i--) {
    
    
        ServiceRecord sr = app.getRunningServiceAt(i);

        // Unless the process is persistent, this process record is going away,
        // so make sure the service is cleaned out of it.
        //非持久化进程
        if (!app.isPersistent()) {
    
    
            //记录服务已停止
            app.stopService(sr);
            //更新绑定的客户端uids
            app.updateBoundClientUids();
        }

        // Sanity check: if the service listed for the app is not one
        // we actually are maintaining, just let it drop.
        //一致性检查
        final ServiceRecord curRec = smap.mServicesByInstanceName.get(sr.instanceName);
        if (curRec != sr) {
    
    
            if (curRec != null) {
    
    
                Slog.wtf(TAG, "Service " + sr + " in process " + app
                        + " not same as in map: " + curRec);
            }
            continue;
        }

        // Any services running in the application may need to be placed
        // back in the pending list.
        //允许重启,但Service崩溃的次数超出重试上限(默认为16),并且它不是系统应用
        if (allowRestart && sr.crashCount >= mAm.mConstants.BOUND_SERVICE_MAX_CRASH_RETRY
                && (sr.serviceInfo.applicationInfo.flags
                    &ApplicationInfo.FLAG_PERSISTENT) == 0) {
    
    
            ... //记录
            //停止服务
            bringDownServiceLocked(sr);
        } else if (!allowRestart
                || !mAm.mUserController.isUserRunning(sr.userId, 0)) {
    
    
            //不允许重启或者服务进程所在用户不在运行,停止服务
            bringDownServiceLocked(sr);
        } else {
    
    
            //尝试调度重启服务
            final boolean scheduled = scheduleServiceRestartLocked(sr, true /* allowCancel */);

            // Should the service remain running?  Note that in the
            // extreme case of so many attempts to deliver a command
            // that it failed we also will stop it here.
            if (!scheduled) {
    
     //未调度重启
                //停止服务
                bringDownServiceLocked(sr);
            } else if (sr.canStopIfKilled(false /* isStartCanceled */)) {
    
    
                // Update to stopped state because the explicit start is gone. The service is
                // scheduled to restart for other reason (e.g. connections) so we don't bring
                // down it.
                //将服务的启动状态更新为停止
                sr.startRequested = false;
                ... //记录
            }
        }
    }

    //不允许重启的话
    if (!allowRestart) {
    
    
        //停止所有服务
        app.stopAllServices();
        //清理绑定的客户端uids
        app.clearBoundClientUids();

        // Make sure there are no more restarting services for this process.
        //确保这个进程不再会重启服务,清理所有待重启待启动的服务
        for (int i=mRestartingServices.size()-1; i>=0; i--) {
    
    
            ServiceRecord r = mRestartingServices.get(i);
            if (r.processName.equals(app.processName) &&
                    r.serviceInfo.applicationInfo.uid == app.info.uid) {
    
    
                mRestartingServices.remove(i);
                clearRestartingIfNeededLocked(r);
            }
        }
        for (int i=mPendingServices.size()-1; i>=0; i--) {
    
    
            ServiceRecord r = mPendingServices.get(i);
            if (r.processName.equals(app.processName) &&
                    r.serviceInfo.applicationInfo.uid == app.info.uid) {
    
    
                mPendingServices.remove(i);
            }
        }
    }

    // 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);
        }
    }

    //清理所有执行中的服务
    //这里的执行中指的是有事务正在运行,比如说正在停止过程中,不是指运行中
    app.executingServices.clear();
}

这里做了各种清理工作,客户端进程的清理呀,服务端进程的清理,然后就是Service重启的核心,scheduleServiceRestartLocked方法

//frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
private final boolean scheduleServiceRestartLocked(ServiceRecord r, boolean allowCancel) {
    
    
    //系统正在关机,直接返回
    if (mAm.mAtmInternal.isShuttingDown()) {
    
    
        return false;
    }

    //一致性检查
    ServiceMap smap = getServiceMapLocked(r.userId);
    if (smap.mServicesByInstanceName.get(r.instanceName) != r) {
    
    
        ServiceRecord cur = smap.mServicesByInstanceName.get(r.instanceName);
        Slog.wtf(TAG, "Attempting to schedule restart of " + r
                + " when found in map: " + cur);
        return false;
    }

    final long now = SystemClock.uptimeMillis();

    final String reason;
    if ((r.serviceInfo.applicationInfo.flags
            &ApplicationInfo.FLAG_PERSISTENT) == 0) {
    
     //对于非系统应用
        //服务至少要过多长时间才能重启,默认1000ms
        long minDuration = mAm.mConstants.SERVICE_RESTART_DURATION;
        //服务被杀死重启后需要运行多长时间,默认60s
        long resetTime = mAm.mConstants.SERVICE_RESET_RUN_DURATION;
        boolean canceled = false;

        // Any delivered but not yet finished starts should be put back
        // on the pending list.
        //对应着返回值为START_REDELIVER_INTENT的情况
        final int N = r.deliveredStarts.size();
        if (N > 0) {
    
    
            for (int i=N-1; i>=0; i--) {
    
    
                ServiceRecord.StartItem si = r.deliveredStarts.get(i);
                si.removeUriPermissionsLocked();
                if (si.intent == null) {
    
    
                    // We'll generate this again if needed.
                } else if (!allowCancel || (si.deliveryCount < ServiceRecord.MAX_DELIVERY_COUNT
                        && si.doneExecutingCount < ServiceRecord.MAX_DONE_EXECUTING_COUNT)) {
    
    
                    //如果该启动项的失败次数小于最大容忍次数
                    //MAX_DELIVERY_COUNT默认为3
                    //MAX_DONE_EXECUTING_COUNT默认为6
                    r.pendingStarts.add(0, si);
                    //这种情况下延时是现在距离启动时间的两倍
                    long dur = SystemClock.uptimeMillis() - si.deliveredTime;
                    dur *= 2;
                    if (minDuration < dur) minDuration = dur;
                    if (resetTime < dur) resetTime = dur;
                } else {
    
    
                    //如果该启动项的失败次数大于等于最大容忍次数
                    canceled = true;
                }
            }
            r.deliveredStarts.clear();
        }

        if (allowCancel) {
    
    
            //判断是否应该停止(只考虑非绑定启动的情况)
            final boolean shouldStop = r.canStopIfKilled(canceled);
            if (shouldStop && !r.hasAutoCreateConnections()) {
    
    
                // Nothing to restart.
                //如果应该停止,直接返回
                return false;
            }
            reason = (r.startRequested && !shouldStop) ? "start-requested" : "connection";
        } else {
    
    
            reason = "always";
        }

        r.totalRestartCount++;
        if (r.restartDelay == 0) {
    
     //第一次重启的情况
            r.restartCount++;
            r.restartDelay = minDuration;
        } else if (r.crashCount > 1) {
    
     //Service所在进程在Service运行过程中发生崩溃导致重启的话
            //重启延时为 30min * (崩溃次数 - 1)
            r.restartDelay = mAm.mConstants.BOUND_SERVICE_CRASH_RESTART_DURATION
                    * (r.crashCount - 1);
        } else {
    
     //非第一次重启的情况
            // If it has been a "reasonably long time" since the service
            // was started, then reset our restart duration back to
            // the beginning, so we don't infinitely increase the duration
            // on a service that just occasionally gets killed (which is
            // a normal case, due to process being killed to reclaim memory).
            if (now > (r.restartTime+resetTime)) {
    
    
                //如果服务重启后运行达到了一定时间,则重启延时为
                r.restartCount = 1;
                r.restartDelay = minDuration;
            } else {
    
    
                //如果服务重启后运行没有达到一定时间(短时间内又要重启)
                //则增长重启延时,默认因子为4
                r.restartDelay *= mAm.mConstants.SERVICE_RESTART_DURATION_FACTOR;
                if (r.restartDelay < minDuration) {
    
    
                    r.restartDelay = minDuration;
                }
            }
        }

        //确定重启时间
        r.nextRestartTime = now + r.restartDelay;

        // Make sure that we don't end up restarting a bunch of services
        // all at the same time.
        //确保不会在同一时间启动大量服务
        boolean repeat;
        do {
    
    
            repeat = false;
            final long restartTimeBetween = mAm.mConstants.SERVICE_MIN_RESTART_TIME_BETWEEN;
            for (int i=mRestartingServices.size()-1; i>=0; i--) {
    
    
                ServiceRecord r2 = mRestartingServices.get(i);
                if (r2 != r && r.nextRestartTime >= (r2.nextRestartTime-restartTimeBetween)
                        && r.nextRestartTime < (r2.nextRestartTime+restartTimeBetween)) {
    
    
                    r.nextRestartTime = r2.nextRestartTime + restartTimeBetween;
                    r.restartDelay = r.nextRestartTime - now;
                    repeat = true;
                    break;
                }
            }
        } while (repeat);

    } else {
    
     //对于系统进程,立马重启
        // Persistent processes are immediately restarted, so there is no
        // reason to hold of on restarting their services.
        r.totalRestartCount++;
        r.restartCount = 0;
        r.restartDelay = 0;
        r.nextRestartTime = now;
        reason = "persistent";
    }

    //添加到重启列表中
    if (!mRestartingServices.contains(r)) {
    
    
        r.createdFromFg = false;
        mRestartingServices.add(r);
        r.makeRestarting(mAm.mProcessStats.getMemFactorLocked(), now);
    }

    //取消前台服务通知
    cancelForegroundNotificationLocked(r);

    //通过Handler调度重启
    mAm.mHandler.removeCallbacks(r.restarter);
    mAm.mHandler.postAtTime(r.restarter, r.nextRestartTime);
    r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
    ... //事件记录
    return true;
}

这个方法主要做了几件事情,一是判断服务需不需要重启,二是计算服务的下次重启时间,最后通过Handler执行延时重启

还记得我们前面说的当返回值为START_REDELIVER_INTENT时,不会从ServiceRecord.deliveredStarts中删除启动项吗?这里就体现出了这一点,遍历整个deliveredStarts列表,从中找出符合重启条件的启动项,将其加入到pendingStarts列表中,需要注意的是,在这种情况下,重启延时为现在距离启动时间的两倍,所以一般情况下START_REDELIVER_INTENTSTART_STICKY重启的要更慢

接下来便要判断服务需不需要重启,这里调用了ServiceRecord.canStopIfKilled方法

//frameworks/base/services/core/java/com/android/server/am/ServiceRecord.java
boolean canStopIfKilled(boolean isStartCanceled) {
    
    
    return startRequested && (stopIfKilled || isStartCanceled) && pendingStarts.isEmpty();
}

之前说过,如果返回值为START_STICKYSTART_STICKY_COMPATIBILITY,那这里的stopIfKilled就为false,所以整体会返回false,而对于返回值START_REDELIVER_INTENT而言,之前已经进行过操作,将启动项添加到pendingStarts列表中了,所以只要这里为false,整体就为falsestopIfKilled的值就不重要了

最后就是通过Handler执行延时重启了,这里Handler传入的RunnableServiceRecord.restarter,它是在服务启动,调用retrieveServiceLocked方法时被创建的

//frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
private class ServiceRestarter implements Runnable {
    
    
    private ServiceRecord mService;

    void setService(ServiceRecord service) {
    
    
        mService = service;
    }

    public void run() {
    
    
        synchronized(mAm) {
    
    
            performServiceRestartLocked(mService);
        }
    }
}

可以看到,在一定的延时后,会调用到performServiceRestartLocked方法重启服务

//frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
final void performServiceRestartLocked(ServiceRecord r) {
    
    
    if (!mRestartingServices.contains(r)) {
    
    
        return;
    }
    if (!isServiceNeededLocked(r, false, false)) {
    
    
        // Paranoia: is this service actually needed?  In theory a service that is not
        // needed should never remain on the restart list.  In practice...  well, there
        // have been bugs where this happens, and bad things happen because the process
        // ends up just being cached, so quickly killed, then restarted again and again.
        // Let's not let that happen.
        Slog.wtf(TAG, "Restarting service that is not needed: " + r);
        return;
    }
    try {
    
    
        //参考上一篇文章,Service启动流程
        bringUpServiceLocked(r, r.intent.getIntent().getFlags(), r.createdFromFg, true, false);
    } catch (TransactionTooLargeException e) {
    
    
        // Ignore, it's been logged and nothing upstack cares.
    }
}

最终调用了bringUpServiceLocked方法启动服务,这一部分可以看上一篇文章 Android源码分析 - Service启动流程 中的分析,还记得上一篇文章中分析的realStartServiceLocked方法中,有一个逻辑是:如果Service已经启动,并且没有启动项,则构建一个假的启动参数供onStartCommand使用 吗?之前看到这个逻辑的时候我还有些疑惑为什么需要这样,现在就豁然开朗了,原来这是为Service重启做的逻辑,而对于返回值START_REDELIVER_INTENT而言,pendingStarts列表本身就不为空,直接正常执行启动任务就可以了

总结

至此,整个Service篇章就到此结束了,通过这次的写作,我自身也是受益匪浅,了解到了很多我以前不知道的知识,也纠正了一些我以前错误的认知,如果也能帮到正在看文章的你们,那就再好不过了

猜你喜欢

转载自blog.csdn.net/qq_34231329/article/details/134300268