Quantcast
Channel: CSDN博客移动开发推荐文章
Viewing all articles
Browse latest Browse all 5930

Android 7.0 ActivityManagerService(6) Service相关流程分析

$
0
0

本篇博客旨在分析Android中Service相关的源码流程。

一、基础知识
Service通常被称之为“后台服务”,具体是指其本身的运行并不依赖于用户可视的UI界面。
例如:点击界面的音乐播放键,由Service进行实际的音乐播放工作。即使用户离开此界面,音乐仍能够继续播放。

不过Service与Activity等相同,都是运行于当前进程的主线程中。
因此一些耗时操作一般并没有放在Service中进行,而是在Service中启动一个工作线程来进行实际的操作。

1 Service的注册
在定义Service时,需要在AndroidManifest.xml中进行声明。
只有这样,PKMS在初始化时,才能通过解析AndroidManifest.xml,得到该Service的信息。
在客户端实际使用Service时,将申请服务的请求发往AMS,后者将通过PKMS提供的信息,检索到具体的Service。

Service在AndroidManifest.xml中的声明,语法格式如下所示:

<service android:enabled=["true" | "false"]
    android:exported[="true" | "false"]
    android:icon="drawable resource"
    android:label="string resource"
    android:name="string"
    android:permission="string"
    android:process="string">
    <intent-filter >
        <action android:name="com.android.server.TestService.TestAction" />
    </intent-filter>
</service>

可以看出,Service相关的标签,与android中其它组件基本相同,此处不作赘述。

2 启动方式
一般而言,从Service的启动方式上,可以将Service分为Unbounded Service和Bounded Service。

2.1 Unbounded Service
Unbounded Service是指:客户端调用ContextImpl的startService等函数启动的Service。
这种启动方式的核心代码片段如下:

..............
Intent serviceIntent = new Intent(mContext, TestService.class);
serviceIntent.putExtra("Args", mArgs);
mContext.startService(serviceIntent);
..............

从上面的代码可以看出,客户端组件通过调用startService函数,向Service端发送一个Intent,该Intent中可以携带具体的业务请求信息。
Service启动后,会根据Intent中的请求,执行实际的业务。

通常情况下,Service启动、处理完请求后,并不会返回启动结果(除非在业务逻辑中主动进行通知)。
即使启动Service的应用组件已经被销毁了,服务将一直在后台运行。

因此,当客户端不再需要使用Service的服务时,需要主动调用ContextImpl的stopService函数。
此外,从在Service内部,也可以在执行完具体的业务后,通过stopSelf函数停止其本身。

Unbounded Service的基本实现方式如下所示:

public class TestService extends Service {
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        ...........
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        super.onStartCommand(intent, flags, startId);
        ..............
        return START_STICKY;
    }

     @Override
     public void onDestroy() {
         super.onDestroy();
        ..........
    }
}

其中,onBind函数是Service基类中的唯一抽象方法,子类必须实现。对于Unbounded Service而言,此函数直接返回 null 即可。
onCreate、onStartCommand和onDestroy都是Unbounded Service相应生命周期阶段的回调函数。

当客户端调用startService启动服务时,AMS收到请求信息后,将判断对应Service是否启动过。
如果Service还未启动,将首先回调Service的onCreate函数,然后再执行onStartCommand函数。
当客户端再次调用startService时,AMS判断Service已经启动,将只调用Service的onStartCommand函数。

在Service的onStartCommand函数中,将根据Intent的信息进行实际的业务处理。
注意到onStartCommand函数会返回一个Int型的值,该值与系统的进程管理有关,主要的取值范围如下:
START_STICKY:
当Service因为内存不足而被系统kill后,在接下来的某个时间内,当系统内存足够可用的情况下,系统将会尝试重新创建此Service;
一旦创建成功后,将回调onStartCommand方法,但一般情况下,参数中的Intent将是null。

START_NOT_STICKY:
当Service因为内存不足而被系统kill后,在接下来的某个时间内,即使系统内存足够可用,系统也不会尝试重新创建此Service。

START_REDELIVER_INTENT:
与START_STICKY相同,当Service因为内存不足而被系统kill后,在接下来的某个时间内,当系统内存足够可用的情况下,系统将会尝试重新创建此Service;唯一不同的是,Service创建成功后,回调onStartCommand方法时,传入的参数将是最后一次调用startService时使用的intent。

需要注意的是,只有系统kill掉Service时上述返回值才有意义,如果是人为地kill掉Service进程,系统不会按照onStartCommand的返回值重启Service。

最后,客户端无论调用多少次startService,只需要一次stopService即可将此Service终止(毕竟onCreate函数也之调用过一次),此时AMS将回调Service的onDestroy函数。

2.2 Bounded Service
Bounded Service一般使用过程如下:
1、服务端定义继承于基类Service的服务,并重写其onBind方法。
在此方法中,需要返回具体的Binder对象供客户端使用。

2、客户端通过实现ServiceConnection接口,自定义ServiceConnection对象,
在其中实现onServiceConnected函数,用于回调获取服务端提供的Binder对象。
同时,客户端也可以选择性地实现onServiceDisconnected接口,以便在与Service解绑时执行一些操作。

3、客户端调用bindService函数与Service端绑定,该函数的参数中包含服务对应的Intent和自定义的ServiceConnection对象。
与Unbounded Service一样,若Service未启动,AMS将负责启动Service,然后才会调用Service的onBind方法,得到服务端返回Binder对象。
一旦得到Binder对象后,AMS将回调ServiceConnection中实现的onServiceConnected函数,将Binder对象返回给客户端。

4、客户端得到Binder对象后,就可以通过Binder对象调用Service提供的公有函数,完成实际的业务请求。
Service端收到业务请求后,就可以执行对应的处理。

5、当客户端不再需要使用服务时,就需要通过调用unbindService函数,解除与Service的绑定。
若客户端实现了ServiceConnection的onServiceDisconnected接口,那么与Service解绑后,onServiceDisconnected将被AMS回调。

网上使用Bounded Service的代码示例较多,此处就不再具体给出,可以参考这篇博客Android总结篇系列:Android Service
我们仅看看源码中的使用方式,例如在packages/services/mms/src/com/android/mms/service/SendRequest.java中:

/**
* Sends the MMS through through the carrier app.
*/
private final class CarrierSendManager extends CarrierMessagingServiceManager {
    ........
    void sendMms(Context context, String carrierMessagingServicePackage,
            CarrierSendCompleteCallback carrierSendCompleteCallback) {
        mCarrierSendCompleteCallback = carrierSendCompleteCallback;
        //调用父类CarrierMessagingServiceManager的bindToCarrierMessagingService函数
        if (bindToCarrierMessagingService(context, carrierMessagingServicePackage)) {
            .............
        } else {
            ..............
        }
    }
}

看看bindToCarrierMessagingService函数:

public boolean bindToCarrierMessagingService(Context context, String carrierPackageName) {
    .........
    //显示指定服务的action和package
    Intent intent = new Intent(CarrierMessagingService.SERVICE_INTERFACE);
    intent.setPackage(carrierPackageName);
    //客户端定义自己的ServiceConnection
    mCarrierMessagingServiceConnection = new CarrierMessagingServiceConnection();

    //作为客户段绑定服务端
    return context.bindService(intent, mCarrierMessagingServiceConnection,
            Context.BIND_AUTO_CREATE);
}

根据IntentAMS将绑定CarrierMessagingService,其onBind函数如下:

public @Nullable IBinder onBind(@NonNull Intent intent) {
    if (!SERVICE_INTERFACE.equals(intent.getAction())) {
        return null;
    }
    //mWrapper的类型为ICarrierMessagingWrapper,继承ICarrierMessagingService.Stub
    //即以AIDL的方式返回Binder对象
    return mWrapper;
}

最后看看客户端CarrierMessagingServiceConnection的onServiceConnected函数:

public void onServiceConnected(ComponentName name, IBinder service) {
    //按照AIDL的规则,得到Binder对象
    //之后,客户端就可以按照AIDL定义的接口,调用服务端的接口
    onServiceReady(ICarrierMessagingService.Stub.asInterface(service));
}

3 生命周期
这里写图片描述

两种Service生命周期对应的回调函数,可以用上面这张比较经典的图来表示,其中:
Unbounded Service回调函数的顺序依次为:onCreate、onStartCommand、onDestroy;
Bounded Service回调函数的顺序依次为:onCreate、onBind、onUnbind、onDestroy。
后文分析源码时,可以看到具体的调用过程,此处不做赘述。

4 显示启动和隐式启动
最后谈一下Service的显示启动和隐式启动。

4.1 显示启动
显示启动是指:
客户端将service的具体名称写入到Intent中,此时AMS就可以直接根据名称来找到对应的service。

代码示例:

//1、startService显示启动服务
...........
Intent startIntent = new Intent();
ComponentName componentName = new ComponentName(
        "com.android.server",
        "com.android.server.TestService");
startIntent.setComponent(componentName);
mContext.startService(startIntent);
............

可以看到显示启动服务,就是在Intent中指定ComponentName。
ComponentName由具体的包名和类名组成。

如果启动的service与当前组件在同一个包内,也可以使用下述方式显示启动service:

//2、startService显示启动同一个包中的服务
...........
Intent startIntent = new Intent(mContext, TestService.class);
mContext.startService(startIntent);
............

同样,bindService也可以显示启动服务,对应的写法如下:

//3、bindService显示启动服务
............
Intent bindIntent = new Intent();
ComponentName componentName = new ComponentName(
        "com.android.server",
        "com.android.server.TestService");
bindIntent.setComponent(componentName);
mContext.bindService(bindIntent, mConnection, Context.BIND_AUTO_CREATE);
............

4.2 隐式启动
隐示启动是指:
客户端通过在intent中添加service申明的Action,此时AMS通过Action来匹配具体的service。
这种启动方式要求,service在定义Action时,要尽可能的和其它服务区分开来。
通常来说,Action将被命名为具体包名、类名和Action名的组合。

代码示例:

............
Intent startIntent = new Intent();
startIntent.setAction("com.android.server.TestService.TestAction");
mContext.startService(startIntent);
............

需要注意的是:Android 5.0以后,只能以显示方式来启动Service,隐式启动服务将抛出异常。

接下来,我们分析一下这两种类型的服务对应的源码流程。

二、Unbounded Service的启动流程

1 ContextImpl中的startService
我们从ContextImpl中的startService函数入手,看看Unbounded Service的启动流程。

public ComponentName startService(Intent service) {
    .............
    return startServiceCommon(service, mUser);
}

private ComponentName startServiceCommon(Intent service, UserHandle user) {
    try {
        //判断Intent中是否符合要求
        validateServiceIntent(service);

        //Intent可能跨进程传输,因此先要做一下安全性检查
        service.prepareToLeaveProcess(this);

        //通过AMS的接口拉起服务
        ComponentName cn = ActivityManagerNative.getDefault().startService(
                mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
                        getContentResolver()), getOpPackageName(), user.getIdentifier());
        ...............
        return cn;
    } catch (RemoteException e) {
        ................
    }
}

从上面的代码可以看出,拉起服务还是要依赖于AMS的接口。
在这里,我们进一步看看validateServiceIntent函数:

private void validateServiceIntent(Intent service) {
    //Intent中既没有指定Component,也没有指定Package,即以隐式启动的方式拉起服务
    if (service.getComponent() == null && service.getPackage() == null) {
        //当版本大于Android L,即Android 5.0时,会抛出异常
        if (getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP) {
            IllegalArgumentException ex = new IllegalArgumentException(
                    "Service Intent must be explicit: " + service);
            throw ex;
        } else {
            //低版本只是打印log而已
            Log.w(TAG, "Implicit intents with startService are not safe: " + service
                    + " " + Debug.getCallers(2, 3));
        }
    }
}

validateServiceIntent就是上文提到的,Android 5.0后不再支持隐式启动Service的原因。

2 AMS中的startService
接下来,我们看看AMS中的startService函数:

public ComponentName startService(IApplicationThread caller, Intent service,
        String resolvedType, String callingPackage, int userId)
        throws TransactionTooLargeException {
    //参数有效性检查
    .................
    synchronized(this) {
        ..........
        //mServices在AMS初始化时得到,类型为ActiveServices
        ComponentName res = mServices.startServiceLocked(caller, service,
                resolvedType, callingPid, callingUid, callingPackage, userId);
        ..........
        return res;
    }
}

2.1 ActiveServices中的startServiceLocked
ActiveServices在AMS初始化时创建,用于管理AMS启动的Service。
上述代码进行参数有效性检查后,将调用ActiveServices的startServiceLocked函数。
我们分段看看startServiceLocked函数:

2.1.1 startServiceLocked Part-I

ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
        int callingPid, int callingUid, String callingPackage, final int userId)
        throws TransactionTooLargeException {
    ................
    final boolean callerFg;
    if (caller != null) {
        //通过AMS得到调用方的进程信息
        final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
        ................
        //判断调用方是否属于前台进程
        callerFg = callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND;
    } else {
        callerFg = true;
    }

    //检索待启动的Service
    ServiceLookupResult res =
            retrieveServiceLocked(service, resolvedType, callingPackage,
                    callingPid, callingUid, userId, true, callerFg, false);
    ..................
    //从ServiceLookupResult中取出ServiceRecord
    ServiceRecord r = res.record;
    .................

startServiceLocked函数的第一部分,主要是利用参数信息检索出待启动的Service,这部分工作主要由retrieveServiceLocked函数完成。
由于retrieveServiceLocked使用的频率较高(后文还会遇到),同时涉及到ActivesService管理Service的一些数据结构,
因此这里深入分析一下该函数:

private ServiceLookupResult retrieveServiceLocked(.......) {
    ServiceRecord r = null;
    ..........
    //得到当前用户的UserId
    userId = mAm.mUserController.handleIncomingUser(callingPid, callingUid, userId, false,
            ActivityManagerService.ALLOW_NON_FULL_IN_PROFILE, "service", null);

    //每个UserId有对应的ServiceMap,统一保存在ActiveServices中
    ServiceMap smap = getServiceMap(userId);

    //对于显示启动
    final ComponentName comp = service.getComponent();
    if (comp != null) {
        //根据ComponentName从ServiceMap中取出对应的ServiceRecord
        r = smap.mServicesByName.get(comp);
    }

    //对于隐式启动
    if (r == null && !isBindExternal) {
        Intent.FilterComparison filter = new Intent.FilterComparison(service);
        //根据Intent对应的Filter,从ServiceMap中取出匹配的ServiceRecord
        r = smap.mServicesByIntent.get(filter);
    }

    //特殊情况的处理
    //对于包含FLAG_EXTERNAL_SERVICE的service,将运行于调用方进程中
    //对于这种特殊服务,
    //如果根据Component或Filter找到了一个正在运行的Service,但其运行进程与当前调用进程不一致
    //那么必须重新在调用进程中创建该ServiceRecord,于是将r置为null
    if (r != null && (r.serviceInfo.flags & ServiceInfo.FLAG_EXTERNAL_SERVICE) != 0
            && !callingPackage.equals(r.packageName)) {
        // If an external service is running within its own package, other packages
        // should not bind to that instance.
        r = null;
    }

    //以上均是在缓存信息中,查找ServiceRecord
    //如果查询不到,则必须通过PKMS进行查找
    if (r == null) {
        try {
            //PKMS根据参数得到对应Pkg中Serivce的ResolveInfo
            ResolveInfo rInfo = AppGlobals.getPackageManager().resolveService(service,
                    resolvedType, ActivityManagerService.STOCK_PM_FLAGS
                            | PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
                    userId);

            //从ResolveInfo中取出ServiceInfo
            ServiceInfo sInfo =
                    rInfo != null ? rInfo.serviceInfo : null;

            //构造出Service对应的ComponentName
            ComponentName name = new ComponentName(
                    sInfo.applicationInfo.packageName, sInfo.name);

            //特殊情况处理
            if ((sInfo.flags & ServiceInfo.FLAG_EXTERNAL_SERVICE) != 0) {
                if (isBindExternal) {
                    ..............
                    // Run the service under the calling package's application.
                    //FLAG_EXTERNAL_SERVICE将运行在调用方进程中,此处就是修改PKMS检索出的ServiceInfo
                    //先得到调用方的应用信息
                    ApplicationInfo aInfo = AppGlobals.getPackageManager().getApplicationInfo(
                            callingPackage, ActivityManagerService.STOCK_PM_FLAGS, userId);
                    ............
                    //将ServiceInfo中的信息,改为调用方应用的信息
                    sInfo = new ServiceInfo(sInfo);
                    sInfo.applicationInfo = new ApplicationInfo(sInfo.applicationInfo);
                    sInfo.applicationInfo.packageName = aInfo.packageName;
                    sInfo.applicationInfo.uid = aInfo.uid;
                    name = new ComponentName(aInfo.packageName, name.getClassName());
                    service.setComponent(name);
                } else {
                    //抛出异常
                    .....
                }
            } else if(isBindExternal) {
                //抛出异常
                ............
            }

            //多用户的处理
            if (userId > 0) {
                //检查服务是否为单例且可被调用的
                if (mAm.isSingleton(sInfo.processName, sInfo.applicationInfo,
                        sInfo.name, sInfo.flags)
                        && mAm.isValidSingletonCall(callingUid, sInfo.applicationInfo.uid)) {
                    //对于多用户而言,每个用户启动的服务,运行于对应用户所在进程组中
                    //但如果待启动服务为单例的,那么该服务还是得运行在系统用户的进程组中
                    //于是此次将userId置为0
                    userId = 0;

                    //ServiceMap都被调整为系统用户对应的
                    smap = getServiceMap(0);
                }
                sInfo = new ServiceInfo(sInfo);
                //此处使用了userId
                sInfo.applicationInfo = mAm.getAppInfoForUser(sInfo.applicationInfo, userId);
            }

            r = smap.mServicesByName.get(name);
            if (r == null && createIfNeeded) {
                ..............
                //创建出对应的ServiceRecord
                r = new ServiceRecord(mAm, ss, name, filter, sInfo, callingFromFg, res);
                ..............
                //保存到ServiceMap中
                smap.mServicesByName.put(name, r);
                smap.mServicesByIntent.put(filter, r);
            }
        } catch(RemoteException ex) {
            ...........
        }
    }

    if (r != null) {
        //进行一些权限检查和有效性检查
        .................

        //没有问题时,返回正常结果
        return new ServiceLookupResult(r, null);
    }
    return null;
}

retrieveServiceLocked函数看起来比较长,但逻辑还是比较清晰的,最主要的步骤是:
1、从ActiveServices保存的一些服务对应的记录信息中,找出ServiceRecord;
2、如果没有找到ServiceRecord,就通过PKMS找出对应的Service信息,然后重新构建出ServiceRecord;
3、将ServiceRecord保存到ActiveServices的数据结构中。

其中,由于考虑到了带有FLAG_EXTERNAL_SERVICE的Service及单例Service的情况,
因此单独进行了处理,在了解整体逻辑后,单独看这些特殊处理还是比较好理解的。

ActiveServices中,保存ServiceRecord涉及的数据结构主要如下图所示:

2.1.2 startServiceLocked Part-II

接下来我们继续看看startServiceLocked下一部分的内容:

    //进行一些检查工作
    .............

    //如果这个服务在重启列表中,清空对应的信息
    if (unscheduleServiceRestartLocked(r, callingUid, false)) {
        .................
    }

    r.lastActivity = SystemClock.uptimeMillis();
    r.startRequested = true;
    r.delayedStop = false;

    //startService可以多次向Service传递信息,每次的信息都是一个StartItem,对应着一个StartId
    r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
            service, neededGrants));
    ............
    //addToStarting决定是否将待启动的Service
    //加入到ActiveServices维护的mStartingBackground队列
    boolean addToStarting = false;

    //如果启动服务的不是前台进程
    //同时服务对应的ServiceRecord中没有记录对应进程的信息(即初次使用)
    if (!callerFg && r.app == null
            //并且user已经启动过其它进程
            && mAm.mUserController.hasStartedUserState(r.userId)) {

        //通过AMS查询Service对应的进程信息
        ProcessRecord proc = mAm.getProcessRecordLocked(r.processName, r.appInfo.uid, false);

        //若Service对应的进程未启动,或优先级过低,则有可能需要延迟启动服务
        if (proc == null || proc.curProcState > ActivityManager.PROCESS_STATE_RECEIVER) {
            // If this is not coming from a foreground caller, then we may want
            // to delay the start if there are already other background services
            // that are starting. This is to avoid process start spam when lots
            // of applications are all handling things like connectivity broadcasts.
            .....................
            if (r.delayed) {
                // This service is already scheduled for a delayed start; just leave
                // it still waiting.
                return r.name;
            }

            //若当前用户启动的后台服务数量过多,则延迟启动服务
            if (smap.mStartingBackground.size() >= mMaxStartingBackground) {
                ................
                smap.mDelayedStartList.add(r);
                r.delayed = true;
                return r.name;
            }
            ..............
            addToStarting = true;
        } else if (proc.curProcState >= ActivityManager.PROCESS_STATE_SERVICE) {
            addToStarting = true;
            ................
        } ..........
        ............
    } ............
    ...............
    return startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
}

上面这段代码主要是:判断当前Service是否需要延迟启动。
若需要延迟启动,则将ServiceRecord保存到smap中的mDelayedStartList中,并结束本启动流程;
否则,调用startServiceInnerLocked函数,进入启动Service的下一个阶段。

2.2 ActiveServices中的startServiceInnerLocked
接下来,我们看看startServiceInnerLocked函数对应的流程:

ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
        boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
    ServiceState stracker = r.getTracker();
    if (stracker != null) {
        //更新ServiceRecord的ServiceState
        stracker.setStarted(true, mAm.mProcessStats.getMemFactorLocked(), r.lastActivity);
    }
    r.callStart = false;
    ..................
    //主要工作通过bringUpServiceLocked函数完成
    String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
    ..................
    //上文提到的,后台进程启动的service才有可能将addToStarting置为true
    if (r.startRequested && addToStarting) {
        boolean first = smap.mStartingBackground.size() == 0;

        //将ServiceRecord加入到smap中的mStartingBackground中
        smap.mStartingBackground.add(r);

        //设置启动Service的超时时间
        r.startingBgTimeout = SystemClock.uptimeMillis() + BG_START_TIMEOUT;
        .............
        if (first) {
            //first为true,说明之前mStartingBackground中的Service处理完毕
            //调用smap的rescheduleDelayedStarts函数
            smap.rescheduleDelayedStarts();
        }
    } else if (callerFg) {
        //若当前Service被后台进程启动过,现在重新被前台进程启动
        //则将其从mStartingBackground中移除,并调用rescheduleDelayedStarts函数(后台服务少了一个,故可能可以继续处理等待的延迟服务)
        //若mDelayedStartList存在该服务的记录,移除对应的信息
        smap.ensureNotStartingBackground(r);
    }

    return r.name;
}

从上面的代码可以看出,启动Service的流程中,接下来的工作主要将由bringUpServiceLocked函数来完成。
在进一步分析bringUpServiceLocked函数前,我们先来看看ActiveServices内部类ServiceMap中的rescheduleDelayedStarts函数。
这个函数遇见的频率比较高,值得深入分析一下:

void rescheduleDelayedStarts() {
    //前面的注释已经提到过,后台进程启动Service超时会发送MSG_BG_START_TIMEOUT消息
    //该消息被处理时,也会调用rescheduleDelayedStarts函数
    //因此,进入该函数时,先移除掉该信息
    removeMessages(MSG_BG_START_TIMEOUT);

    final long now = SystemClock.uptimeMillis();
    for (int i=0, N=mStartingBackground.size(); i<N; i++) {
        ServiceRecord r = mStartingBackground.get(i);

        //将超时的Service从mStartingBackground中移除
        if (r.startingBgTimeout <= now) {
            Slog.i(TAG, "Waited long enough for: " + r);
            mStartingBackground.remove(i);
            N--;
            i--;
        }
    }

    //存在延迟Service,同时后台Service较少时
    while (mDelayedStartList.size() > 0
            && mStartingBackground.size() < mMaxStartingBackground) {
        ServiceRecord r = mDelayedStartList.remove(0);
        .................
        r.delayed = false;
        try {
            //启动延迟Service,启动后会修改mStartingBackground.size
            startServiceInnerLocked(this, r.pendingStarts.get(0).intent, r, false, true);
        } catch (TransactionTooLargeException e) {
            ..........
        }

        if (mStartingBackground.size() > 0) {
            ServiceRecord next = mStartingBackground.get(0);
            //决定延迟发送消息的时间
            long when = next.startingBgTimeout > now ? next.startingBgTimeout : now;
            ................
            Message msg = obtainMessage(MSG_BG_START_TIMEOUT);
            //一旦超时,就会发送MSG_BG_START_TIMEOUT
            sendMessageAtTime(msg, when);
        }
        .....................
    }
}

rescheduleDelayedStarts的流程还是比较好理解的,主要工作其实就是两个:
1、判断mStartingBackground中启动的Service是否超时
2、判断能否启动mDelayedStartList中,被延迟启动的服务。

2.3 ActiveServices中的bringUpServiceLocked
现在我们回过头来,继续跟进启动Service接下来的流程,即bringUpServiceLocked函数:

private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
        boolean whileRestarting, boolean permissionsReviewRequired)
        throws TransactionTooLargeException {
    ....................

    //处理Service已经启动的情况
    //此时只是发送新的StartItem
    if (r.app != null && r.app.thread != null) {
        //将调用sendServiceArgsLocked函数,后文会遇到
        sendServiceArgsLocked(r, execInFg, false);
        return null;
    }

    if (!whileRestarting && r.restartDelay > 0) {
        // If waiting for a restart, then do nothing.
        return null;
    }
    .............

    //以下的代码主要是为了保持数据的一致性
    //为了健壮,变得冗余

    // We are now bringing the service up, so no longer in the
    // restarting state.
    if (mRestartingServices.remove(r)) {
        r.resetRestartCounter();
        clearRestartingIfNeededLocked(r);
    }

    // Make sure this service is no longer considered delayed, we are starting it now.
    if (r.delayed) {
        ............
        getServiceMap(r.userId).mDelayedStartList.remove(r);
        r.delayed = false;
    }

    // Make sure that the user who owns this service is started.  If not,
    // we don't want to allow it to run.
    if (!mAm.mUserController.hasStartedUserState(r.userId)) {
        ...........
        bringDownServiceLocked(r);
        return msg;
    }

    // Service is now being launched, its package can't be stopped.
    try {
        AppGlobals.getPackageManager().setPackageStoppedState(
                r.packageName, false, r.userId);
    } catch (RemoteException e) {
    } catch (IllegalArgumentException e) {
        .............
    }

    final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
    final String procName = r.processName;
    ProcessRecord app;

    if (!isolated) {
        //取出ServiceRecord对应的进程信息
        app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
        ..............
        //如果对应进程已经启动
        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) {
                ...............
            }
        }
    } 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.
        //对于“孤立”的Service而言,其ServiceRecord中记录着它将运行的进程
        //此处,若isolatedProc为null,则表明需要启动新的进程; 不为null,说明正在等待进程的启动
        app = r.isolatedProc;
    }

    // Not running -- get it started, and enqueue this service record
    // to be executed when the app comes up.
    if (app == null && !permissionsReviewRequired) {
        //启动服务对应的进程
        if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
                "service", r.name, false, isolated, false)) == null) {
            ............
            //进程启动失败,将停止服务
            bringDownServiceLocked(r);
            return msg;
        }
        if (isolated) {
            r.isolatedProc = app;
        }
    }

    if (!mPendingServices.contains(r)) {
        //mPendingServices保存待启动服务,当进程启动后,会重新启动该服务
        mPendingServices.add(r);
    }

    //服务还未完成启动,就收到结束请求时,会直接停止该服务
    if (r.delayedStop) {
        // Oh and hey we've already been asked to stop!
        r.delayedStop = false;
        if (r.startRequested) {
            ..........
            stopServiceLocked(r);
        }
    }

    return null;
}

bringUpServiceLocked函数比较长,主要是其内部包含了多个场景下的处理流程,其中比较主要的是:
1、service已经启动过,则调用sendServiceArgsLocked函数,将新的待处理信息发送给Service;
2、service未启动过,但对应的进程已启动,那么调用realStartServiceLocked函数,启动服务即可;
3、service对应的进程并没有启动,那么先启动进程。

这里我们跟进第2种场景的流程即可。
对于第1种场景,当第2种场景中的服务启动后,仍将利用sendServiceArgsLocked函数中的流程,将Intent消息发往Service处理;
对于第3种场景,当进程启动后,与之前的博客分析Activity和BroadcastReceiver流程类似,
在AMS的attachApplicationLocked函数中,将启动等待的service。这部分代码如下所示:

private final boolean attachApplicationLocked(IApplicationThread thread,
        int pid) {
    ................
    // Find any services that should be running in this process...
    if (!badApp) {
        try {
            //attachApplicationLocked处理等待的启动服务
            //其中将所有mPendingServices与进程信息进行匹配,然后调用realStartServiceLocked启动对应Service
            didSomething |= mServices.attachApplicationLocked(app, processName);
        } catch (Exception e) {
            ................
            badApp = true;
        }
    }
    .................
}

2.4 ActiveServices中的realStartServiceLocked
现在我们来看看ActiveServices中的realStartServiceLocked函数:

private final void realStartServiceLocked(ServiceRecord r,
        ProcessRecord app, boolean execInFg) throws RemoteException {
    ............
    //对服务的状态进行记录
    bumpServiceExecutingLocked(r, execInFg, "create");

    //更新进程对应的优先级信息
    //这两个函数多次出现,以后分析AMS进程管理时,单独分析
    mAm.updateLruProcessLocked(app, false, null);
    mAm.updateOomAdjLocked();

    boolean created = false;
    try {
        ................
        //更改进程状态为PROCESS_STATE_SERVICE
        app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);

        //Binder通信,发送消息给进程的ApplicationThread,创建服务
        app.thread.scheduleCreateService(r, r.serviceInfo,
                mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
                app.repProcState);
        .............
        created = true;
    } catch (DeadObjectException e) {
        .........
        //失败,此处会kill掉进程
        mAm.appDiedLocked(app);
        throw e;
    } finally {
        //服务创建失败
        if (!created) {
            // Keep the executeNesting count accurate.
            //更新相关的统计信息
            final boolean inDestroying = mDestroyingServices.contains(r);
            serviceDoneExecutingLocked(r, inDestroying, inDestroying);
        }

        // Cleanup.
        if (newService) {
            app.services.remove(r);
            r.app = null;
        }

        // Retry.
        if (!inDestroying) {
            //安排服务重启
            //将根据服务的重启次数,决定是否继续重启,以及重启的时间间隔
            scheduleServiceRestartLocked(r, false);
        }
    }

    ...............
    //Service被绑定过,才会调用onBind函数,后文介绍Bounded Service会遇到相关流程
    requestServiceBindingsLocked(r, execInFg);

    //如果客户端Bind Service成功,按需更新服务端进程优先级
    updateServiceClientActivitiesLocked(app, null, true);

    // If the service is in the started state, and there are no
    // pending arguments, then fake up one so its onStartCommand() will
    // be called.
    if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
        //构造StartItem
        r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
                null, null));
    }

    //果然会调用到sendServiceArgsLocked发送参数
    sendServiceArgsLocked(r, execInFg, true);

    //如果Service是延迟启动的,那么此时可以将其从mDelayedStartList移除
    if (r.delayed) {
        ..........
        getServiceMap(r.userId).mDelayedStartList.remove(r);
        r.delayed = false;
    }

    //若Service被要求停止,那么结束服务
    if (r.delayedStop) {
        ......
        r.delayedStop = false;
        if (r.startRequested) {
            ...........
            stopServiceLocked(r);
        }
    }
}

从代码来看,对于Unbounded Service而言,realStartServiceLocked函数最主要的工作是:
1、利用bumpServiceExecutingLocked函数,记录ServiceRecord的执行状态;
2、利用scheduleCreateService函数,创建出Service对象;
3、利用sendServiceArgsLocked函数,将Intent中的信息递交给Service处理。

接下来,我们重点来分析一下这三个函数。

2.4.1 bumpServiceExecutingLocked
这个函数被调用的频率比较高,当AMS向Service发送命令时,就会利用该函数修改ServiceRecord中的一些信息:

private final void bumpServiceExecutingLocked(ServiceRecord r, boolean fg, String why) {
    ..............
    long now = SystemClock.uptimeMillis();

    //executeNesting用于记录Service待处理的请求数量
    if (r.executeNesting == 0) {
        //处理第一个命令时,即初次启动Service时

        r.executeFg = fg;
        ServiceState stracker = r.getTracker();
        if (stracker != null) {
            //记录时间
            stracker.setExecuting(true, mAm.mProcessStats.getMemFactorLocked(), now);
        }

        if (r.app != null) {
            //更新进程ProcessRecord中关于Service的记录
            r.app.executingServices.add(r);
            r.app.execServicesFg |= fg;

            if (r.app.executingServices.size() == 1) {
                //设置启动Service超时的时间
                //即Service初次启动时,如果进程中只有这一个Service
                //那么一旦启动超时,将触发AMS发送ANR
                scheduleServiceTimeoutLocked(r.app);
            }
        }
    } else if (r.app != null && fg && !r.app.execServicesFg) {
        //前台进程向后台服务发送命令时,也会设置超时时间,一旦超时,也会ANR

        //发送一次后,该值变为true,相当与变成前台服务了
        r.app.execServicesFg = true;

        scheduleServiceTimeoutLocked(r.app);
    }
    r.executeFg |= fg;
    //每处理一个命令,executeNesting均会+1
    r.executeNesting++;
    r.executingStart = now;
}

bumpServiceExecutingLocked函数主要用于将进程的ProcessRecord信息,与ServiceRecord关联起来。
同时,更新ServiceRecord中的一些信息,并设置命令超时的时间。

这里我们跟进一下scheduleServiceTimeoutLocked函数,看看Service命令执行超时的后果:

void scheduleServiceTimeoutLocked(ProcessRecord proc) {
    //安排Service执行命令的超时时间,那么进程得存活,同时其中存在运行的Service
    if (proc.executingServices.size() == 0 || proc.thread == null) {
        return;
    }

    long now = SystemClock.uptimeMillis();
    Message msg = mAm.mHandler.obtainMessage(
                ActivityManagerService.SERVICE_TIMEOUT_MSG);
    msg.obj = proc;
    mAm.mHandler.sendMessageAtTime(msg,
            //前台超时的时间为20s,后台为200s
            proc.execServicesFg ? (now+SERVICE_TIMEOUT) : (now+ SERVICE_BACKGROUND_TIMEOUT));
}

一旦Service执行命令超时,SERVICE_TIMEOUT_MSG将触发ActiveServices的serviceTimeout函数:

void serviceTimeout(ProcessRecord proc) {
    String anrMessage = null;

    synchronized(mAm) {
        if (proc.executingServices.size() == 0 || proc.thread == null) {
            return;
        }

        final long now = SystemClock.uptimeMillis();
        //在maxTime之前开始执行的命令都是超时的
        final long maxTime =  now -
                (proc.execServicesFg ? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT);
        ServiceRecord timeout = null;
        long nextTime = 0;
        for (int i=proc.executingServices.size()-1; i>=0; i--) {
            ServiceRecord sr = proc.executingServices.valueAt(i);
            if (sr.executingStart < maxTime) {
                //找到超时的ServiceRecord
                timeout = sr;
                break;
            }

            if (sr.executingStart > nextTime) {
                //nextTime的值,等于所有待处理Service命令,启动时间的最大值
                //用于触发下一次超时处理
                nextTime = sr.executingStart;
            }
        }

        //如果超时,同时进程还存活着
        if (timeout != null && mAm.mLruProcesses.contains(proc)) {
            //打印dump信息等
            ..........
            anrMessage = "executing service " + timeout.shortName;
        } else {
            //没有超时,则根据nextTime定义下一次发送SERVICE_TIMEOUT_MSG的时间
            Message msg = mAm.mHandler.obtainMessage(
                    ActivityManagerService.SERVICE_TIMEOUT_MSG);
            msg.obj = proc;
            mAm.mHandler.sendMessageAtTime(msg, proc.execServicesFg
                    ? (nextTime+SERVICE_TIMEOUT) : (nextTime + SERVICE_BACKGROUND_TIMEOUT));
        }
    }

    if (anrMessage != null) {
        //发生了ANR,会杀死进程,记录和显示一些信息
        mAm.mAppErrors.appNotResponding(proc, null, null, false, anrMessage);
    }
}

2.4.2 scheduleCreateService
现在我们回过头来看看realStartServiceLocked调用的scheduleCreateService函数。

调用ApplicationThread的scheduleCreateService函数后,将向ActivityThread发送H.CREATE_SERVICE消息,
由ActivityThread的handleCreateService函数进行处理。

private void handleCreateService(CreateServiceData data) {
    ....................
    //得到Service对应的LoadedApk信息
    LoadedApk packageInfo = getPackageInfoNoCheck(
            data.info.applicationInfo, data.compatInfo);
    Service service = null;
    try {
        java.lang.ClassLoader cl = packageInfo.getClassLoader();
        //通过反射创建出实例
        service = (Service) cl.loadClass(data.info.name).newInstance();
    } catch (Exception e) {
        ..................
    } 

    try {
        ............
        //创建service的Android运行环境
        ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
        //实际工作类为ContextImpl,其代理设置为service
        context.setOuterContext(service);

        Application app = packageInfo.makeApplication(false, mInstrumentation);

        //此时Service才算运行在Android环境中了
        //此处传递的this是ActivityThread,这就是大家常说的:service也是运行在主线程中的原因
        //因此在service中执行耗时操作,最好也利用HandlerThread
        //例如ConnectivityService、NetworkManagementService都是这么干的
        service.attach(context, this, data.info.name, data.token, app,
                ActivityManagerNative.getDefault());

        //调用Service的onCreate函数
        service.onCreate();

        //mServices中存储了ActivityThread中运行的服务
        //key值为Service对应的IBinder,是从Service对应的ServiceRecord中取出的
        mServices.put(data.token, service);
        try {
            //通知AMS service启动成功,进行取消超时消息等操作
            //后文再分析该函数
            ActivityManagerNative.getDefault().serviceDoneExecuting(
                    data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    } catch (Exception e) {
        .............
    }
}

2.4.3 sendServiceArgsLocked
sendServiceArgsLocked函数,需要将Intent信息发送给Service进行处理。

private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
        boolean oomAdjusted) throws TransactionTooLargeException {
    ...............
    //本次需发送的信息,在调用sendServiceArgsLocked前,已经加入到了pendingStarts中
    //通过循环,将pending的信息发送完
    while (r.pendingStarts.size() > 0) {
        ...........
        try {
            //依次取出
            si = r.pendingStarts.remove(0);
            ............
            si.deliveredTime = SystemClock.uptimeMillis();
            //记录发送时间和发送次数
            r.deliveredStarts.add(si);
            si.deliveryCount++;
            ...........
            int flags = 0;
            //发送次数大于1,添加对应flag
            if (si.deliveryCount > 1) {
                flags |= Service.START_FLAG_RETRY;
            }

            //这个应该是service被kill掉后,系统重启服务发送的Intent,于是添加对应的flag
            if (si.doneExecutingCount > 0) {
                flags |= Service.START_FLAG_REDELIVERY;
            }

            //Binder通信给ApplicationThread
            r.app.thread.scheduleServiceArgs(r, si.taskRemoved, si.id, flags, si.intent);
        } ..........
        ...........
    }
}

Service对应进程ApplicationThread的scheduleServiceArgs函数被调用后,将发送H.SERVICE_ARGS消息,
触发其ActivityThread调用handleServiceArgs处理:

private void handleServiceArgs(ServiceArgsData data) {
    //取出IBinder对应的Service
    Service s = mServices.get(data.token);

    if (s != null) {
        try {
            .........
            int res;
            //通常情况,taskRemoved为false
            if (!data.taskRemoved) {
                //调用Service的onStartCommand函数,处理Intent携带的内容
                res = s.onStartCommand(data.args, data.flags, data.startId);
            } else {
                s.onTaskRemoved(data.args);
                res = Service.START_TASK_REMOVED_COMPLETE;
            }

            //在通知AMS消息处理完成前,现完成本地等待处理的任务
            //这里与启动BroadcastReceiver对应进程的情况相似
            //进程可能是由于创建Service才被启动的,Service处理完毕后,AMS可能进行进程管理
            //杀死Service对应进程,因此先确保工作做完
            QueuedWork.waitToFinish();

            try {
                //再次调用AMS的serviceDoneExecuting函数,通知AMS消息处理完毕
                //本次的flag为SERVICE_DONE_EXECUTING_START
                ActivityManagerNative.getDefault().serviceDoneExecuting(
                        data.token, SERVICE_DONE_EXECUTING_START, data.startId, res);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
            ensureJitEnabled();
        } catch(Exception e) {
            ........
        }
    }
}

不难看出handleServiceArgs函数主要是调用Service的onStartCommand函数处理Intent,
然后再次调用AMS的serviceDoneExecuting函数通知执行结果。

前面我们分析Service的基础知识提到过,onStartCommand函数被调用后,有相应的返回值。
因此我们来看看AMS的serviceDoneExecuting函数,如何处理这部分返回值。

public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
    synchronized(this) {
        ............
        mServices.serviceDoneExecutingLocked((ServiceRecord)token, type, startId, res);
    }
}

AMS还是将Service相关的具体工作交给ActiveServices处理:

void serviceDoneExecutingLocked(ServiceRecord r, int type, int startId, int res) {
    //Service每执行完一次命令都会通知AMS,serviceDoneExecutingLocked将被多次调用
    //因此,该函数中需要处理的场景比较多

    //先判断该Service是否destroy
    boolean inDestroying = mDestroyingServices.contains(r);

    if (r != null) {
        //Service的onStartCommand函数被调用后,通知AMS的type为SERVICE_DONE_EXECUTING_START
        if (type == ActivityThread.SERVICE_DONE_EXECUTING_START) {
            // This is a call from a service start...  take care of
            // book-keeping.
            r.callStart = true;

            //处理onStartCommand的返回值
            switch (res) {
                case Service.START_STICKY_COMPATIBILITY:
                case Service.START_STICKY: {
                    // We are done with the associated start arguments.
                    //找到startId对应的StartItem,并移除(true)
                    r.findDeliveredStart(startId, true);

                    // Don't stop if killed.
                    //这个值置为false后,Service被杀掉还有机会重启
                    r.stopIfKilled = false;
                    break;
                }
                case Service.START_NOT_STICKY: {
                    // We are done with the associated start arguments.
                    //找到startId对应的StartItem,并移除(true)
                    r.findDeliveredStart(startId, true);

                    if (r.getLastStartId() == startId) {
                        // There is no more work, and this service
                        // doesn't want to hang around if killed.
                        //服务kill掉,不再重启
                        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.
                    //找到startId对应的StartItem,不移除(false)
                    ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
                    if (si != null) {
                        si.deliveryCount = 0;
                        si.doneExecutingCount++;
                        // Don't stop if killed.
                        r.stopIfKilled = true;
                    }
                    break;
                }
                //略去不常见的处理
                .............
            }
        } else if (type == ActivityThread.SERVICE_DONE_EXECUTING_STOP) {
            //Service的onStop函数被调用时,通知AMS的type为SERVICE_DONE_EXECUTING_STOP
            //打一些log而已,无实际操作
            ..................
        }
        ..........
        serviceDoneExecutingLocked(r, inDestroying, inDestroying);
        ..........
    } else {
        ........
    }
}

上面的serviceDoneExecutingLocked函数,主要是针对onStartCommand的返回值进行一些操作,
然后调用重载后的serviceDoneExecutingLocked:

private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying,
        boolean finishing) {
    ...............
    //ServiceRecord的一个命令执行完毕,executeNesting -1
    //这些操作与前面提过的bumpServiceExecutingLocked函数,一一对应
    r.executeNesting--;

    //所有命令执行完毕
    if (r.executeNesting <= 0) {
        if (r.app != null) {
            ..............
            r.app.execServicesFg = false;
            //ServiceRecord被从executingServices移除,处理超时消息时,不会处理该Service
            r.app.executingServices.remove(r);

            //整个进程所有的Service命令均处理完毕
            if (r.app.executingServices.size() == 0) {
                ............
                //移除time out消息
                mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);
            } else if (r.executeFg) {
                // Need to re-evaluate whether the app still needs to be in the foreground.
                for (int i=r.app.executingServices.size()-1; i>=0; i--) {
                    if (r.app.executingServices.valueAt(i).executeFg) {
                        //有一个Service是前台服务,则app仍是前台的
                        r.app.execServicesFg = true;
                        break;
                    }
                }
            }

            if (inDestroying) {
                .......
                mDestroyingServices.remove(r);
                r.bindings.clear();
            }
            mAm.updateOomAdjLocked(r.app);
        }

        r.executeFg = false;
        if (r.tracker != null) {
            //更新ServiceRecord的ServiceState
            r.tracker.setExecuting(false, mAm.mProcessStats.getMemFactorLocked(),
                    SystemClock.uptimeMillis());
            if (finishing) {
                r.tracker.clearCurrentOwner(r, false);
                r.tracker = null;
            }
        }

        if (finishing) {
            //若Service结束,将其从进程对应的记录信息中移除
            if (r.app != null && !r.app.persistent) {
                r.app.services.remove(r);
                .............
            }
            r.app = null;
        }
    }
}

从上面的代码可以看出,这个serviceDoneExecutingLocked函数进行的扫尾工作,主要是为了更新ServiceRecord的相关信息。
这些信息将被用于判断Service执行命令时是否超时,同时对进程管理也有一定的影响。

至此,Unbounded Service的启动过程分析完毕。
整个流程中的函数调用关系还是很清晰的,只是涉及到Service状态的管理,于是会有一些琐碎的分支。
其中部分函数,Bounded Service启动时也会调用。

这部分的流程可以简化为下图:

大图链接

三、Unbounded Service的结束流程
接下来,我们看看Unbounded Service的结束流程。

1 ContextImpl中的stopService
与启动流程类似,我们从ContextImpl的stopService函数开始,看看Unbounded Service的结束流程。

public boolean stopService(Intent service) {
    ..............
    //直接调用stopServiceCommon
    return stopServiceCommon(service, mUser);
}

private boolean stopServiceCommon(Intent service, UserHandle user) {
    try {
        //同样确保为L以上,为显示调用
        validateServiceIntent(service);
        ..........
        int res = ActivityManagerNative.getDefault().stopService(.......);
        .........
        return res != 0;
    } catch (RemoteException e) {
        ..............
    }
}

ContextImpl中仅仅检查了Intent的合理性,主要工作仍委托给AMS处理。

2 AMS中的stopService

public int stopService(IApplicationThread caller, Intent service,
        String resolvedType, int userId) {
    //参数检查
    ...........
    synchronized(this) {
        return mServices.stopServiceLocked(caller, service, resolvedType, userId);
    }
}

不出所料,AMS将结束Service的工作交给ActiveServices处理。

int stopServiceLocked(IApplicationThread caller, Intent service,
        String resolvedType, int userId) {
    //参数检查
    ..........
    // If this service is active, make sure it is stopped.
    //前文已经分析过retrieveServiceLocked函数,此处将检索出待停止的ServiceRecord
    ServiceLookupResult r = retrieveServiceLocked(service, resolvedType, null,
            Binder.getCallingPid(), Binder.getCallingUid(), userId, false, false, false);

    if (r != null) {
        if (r.record != null) {
            ..........
            try {
                stopServiceLocked(r.record);
            } finally {
                .........
            }
            return 1;
        }
        return -1;
    }
    return 0;
}

跟进重载后的stopServiceLocked函数:

private void stopServiceLocked(ServiceRecord service) {
    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.
        //这个服务还未启动,将delayedStop置为true
        //当系统处理Service的启动请求后,检验到该标识,会再次调用stopService函数
        ........
        service.delayedStop = true;
        return;
    }
    .............
    //更新ServiceRecord的状态信息
    service.startRequested = false;
    if (service.tracker != null) {
        service.tracker.setStarted(false, mAm.mProcessStats.getMemFactorLocked(),
                SystemClock.uptimeMillis());
    }
    bringDownServiceIfNeededLocked(service, false, false);  
}

上述代码没有什么特别的地方,主要更新ServiceRecord的状态信息,然后调用bringDownServiceIfNeededLocked函数。

3 ActiveServices中的bringDownServiceIfNeededLocked
从函数名可以看出,该函数主要判断能否停止该服务。

private final void bringDownServiceIfNeededLocked(ServiceRecord r, boolean knowConn,
        boolean hasConn) {
    //判断服务是否还有存在的必要
    if (isServiceNeeded(r, knowConn, hasConn)) {
        return;
    }

    // Are we in the process of launching?
    //Service还未启动,不需要停止
    if (mPendingServices.contains(r)) {
        return;
    }

    //进入结束服务的流程
    bringDownServiceLocked(r);
}

上面代码中,主要由isServiceNeeded函数判断Service是否还有存在的必要。
我们分析一下该函数:

//该流程中,参数knowConn和hasConn均为false
private final boolean isServiceNeeded(ServiceRecord r, boolean knowConn, boolean hasConn) {
    // Are we still explicitly being asked to run?
    //在进入bringDownServiceIfNeededLocked函数前,startRequested已经置为false了
    if (r.startRequested) {
        return true;
    }

    // Is someone still bound to us keepign us running?
    if (!knowConn) {
        //如果其它客户端,携带BIND_AUTO_CREATE标志,绑定过该Service
        //那么hasConn被置为true
        hasConn = r.hasAutoCreateConnections();
    }

    if (hasConn) {
        return true;
    }

    return false;
}

通过上述代码,我们知道一个Service如果同时以Bounded Service和Unbounded Service存在,
那么必须解绑后,才能被stopService结束。

4 ActiveServices中的bringDownServiceLocked
接下来,我们继续跟进结束Service流程中的bringDownServiceLocked函数:

private final void bringDownServiceLocked(ServiceRecord r) {
    // Report to all of the connections that the service is no longer
    // available.
    //从之前的isServiceNeeded函数来看
    //只有BIND_AUTO_CREATE创建的ServiceConnection,才能阻止Service被终止
    //因此,Service是可以有普通的ServiceConnection的
    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 {
                //通知客户端,Service不行了
                //其实就是调用客户端ServiceConnection的onServiceDisconnected接口
                cr.conn.connected(r.name, null);
            } catch (Exception e) {
                .............
            }
        }
    }

    // Tell the service that it has been unbound.
    //Unbounded Service也可以被绑定,此处执行unBindService相关的工作
    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 (ibr.hasBound) {
                try {
                    //如前文所术,执行命令时,就会调用bumpServiceExecutingLocked,更新ServiceRecord的状态
                    bumpServiceExecutingLocked(r, false, "bring down unbind");

                    mAm.updateOomAdjLocked(r.app);

                    ibr.hasBound = false;

                    //进行unBindService相关的工作
                    r.app.thread.scheduleUnbindService(r,
                            ibr.intent.getIntent());
                } catch (Exception e) {
                }
            }
        }
    }

    //清除smap等数据结构中的记录
    final ServiceMap smap = getServiceMap(r.userId);
    smap.mServicesByName.remove(r.name);
    smap.mServicesByIntent.remove(r.intent);
    r.totalRestartCount = 0;
    unscheduleServiceRestartLocked(r, 0, true);

    // Also make sure it is not on the pending list.
    for (int i=mPendingServices.size()-1; i>=0; i--) {
        if (mPendingServices.get(i) == r) {
            mPendingServices.remove(i);
            ............
        }
    }
    .................
    if (r.app != null) {
        ...........
        //从进程对应的记录信息中移除Service相关的信息
        r.app.services.remove(r);
        ...........
        if (r.app.thread != null) {
            .............
            try {
                bumpServiceExecutingLocked(r, false, "destroy");

                //待结束的服务加入到mDestroyingServices中
                mDestroyingServices.add(r);

                r.destroying = true;
                mAm.updateOomAdjLocked(r.app);

                //通知进程结束服务
                r.app.thread.scheduleStopService(r);
            } catch() {
                ..........
            }
        } else {
            ..........
        }
    } else {
        ..........
    }
    .................
    //更新ServiceRecord的相关状态
    long now = SystemClock.uptimeMillis();
    if (r.tracker != null) {
        r.tracker.setStarted(false, memFactor, now);
        r.tracker.setBound(false, memFactor, now);
        if (r.executeNesting == 0) {
            r.tracker.clearCurrentOwner(r, false);
            r.tracker = null;
        }
    }

    //一个后台服务结束后,将调用rescheduleDelayedStarts函数
    //启动mDelayedStartList中延迟启动的服务
    smap.ensureNotStartingBackground(r);
}

从上面的代码可以看出,bringDownServiceLocked函数是Service结束流程中的主力(Unbouneed Service和Bounded Service最终均依赖它结束Service流程),
其主要共走包括:
1、通知与Service绑定的客户端,该Service不可用;同时,通知对应进程进行unBindService的工作。
2、通知Service所在进程,调用Service的onDestroy函数。
3、更新ServiceRecord的状态,同时调用ensureNotStartingBackground函数,在必要时启动mDelayedStartList中的服务。

unBindService相关的操作,后文分析Bounded Service的结束流程时还会碰到,此处先略去。
先看看调用ApplicationThread的scheduleStopService函数后的流程。

5 ActivityThread中的handleStopService
ApplicationThread的scheduleStopService函数被调用后,将发送H.STOP_SERVICE消息,触发ActivityThread调用handleStopService处理:

private void handleStopService(IBinder token) {
    //从ActivityThread的记录信息中,移除Service
    Service s = mServices.remove(token);
    if (s != null) {
        try {
            ...........
            //调用Service的onDestroy函数
            s.onDestroy();

            Context context = s.getBaseContext();
            if (context instanceof ContextImpl) {
                inal String who = s.getClassName();
                /进行清除工作
                ((ContextImpl) context).scheduleFinalCleanup(who, "Service");
            }

            //在返回AMS消息前,先完成进程中的重要事件
            QueuedWork.waitToFinish();

            try {
                //前文已经介绍过serviceDoneExecuting函数,通知AMS Service处理完相关的命令
                ActivityManagerNative.getDefault().serviceDoneExecuting(
                        token, SERVICE_DONE_EXECUTING_STOP, 0, 0);
            } catch (RemoteException e) {
                ...............
            }
        } catch(Exception e) {
            ..........
        }
    } else {
        .......
    }
}

从上面的代码可以看出,handleStopService负责调用Service的onDestroy函数,
然后通知ContextImpl进行Service结束后的清理工作,最后通知AMS命令执行完毕。

此处,我们看看ContextImpl的scheduleFinalCleanup函数:

final void scheduleFinalCleanup(String who, String what) {
    //还是依靠ActivityThread进行实际的清理个工作
    mMainThread.scheduleContextCleanup(this, who, what);
}

ActivityThread的scheduleContextCleanup函数,将发送CLEAN_UP_CONTEXT信息,
最终仍会调用ContextImpl的performFinalCleanup函数进行处理。

final void performFinalCleanup(String who, String what) {
    //mPackageInfo的类型为LoadedApk
    //此处getOuterContext传入的是Service
    mPackageInfo.removeContextRegistrations(getOuterContext(), who, what);
}

我们看看LoadedApk中的removeContextRegistrations函数:

public void removeContextRegistrations(Context context,
        String who, String what) {
    ...............
    synchronized (mReceivers) {
        //此时,传入的是Service对应的Context(其实就是Service)
        //因此rmap为null
        ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> rmap =
                mReceivers.remove(context);
        if (rmap != null) {
            for (int i = 0; i < rmap.size(); i++) {
                LoadedApk.ReceiverDispatcher rd = rmap.valueAt(i);
                ...........
                try {
                    //通知AMS移除BroadcastReceiver相关的信息
                    ActivityManagerNative.getDefault().unregisterReceiver(
                            rd.getIIntentReceiver());
                } catch (RemoteException e) {
                    throw e.rethrowFromSystemServer();
                }
            }
            mUnregisteredReceivers.remove(context);
        }
    }

    synchronized (mServices) {
        //只有Bounded Service才会被加入到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);
                ............
                try {
                    //通知AMS, Service解绑
                    ActivityManagerNative.getDefault().unbindService(
                            sd.getIServiceConnection());
                } catch (RemoteException e) {
                    throw e.rethrowFromSystemServer();
                }
                ...........
            }
        }
        mUnboundServices.remove(context);
    }
}

现在我们明白了,scheduleFinalCleanup的工作,主要针对于BroadcastReceiver和Bounded Service,
目的是清理它们在AMS中的相关信息。

至此,Unbounded Service的主要流程分析完毕,在之前分析startService的基础上,理解stopService的流程还是比较容易的。
以下是stopService中最主要步骤对应的流程图:

大图链接

四、Bounded Service的启动流程
分析完Unbounded Service的基本流程后,我们再来看看Bounded Service相关的流程。

1 ContextImpl的bindService
先从ContextImpl的bindService开始,分析Bounded Service的启动流程。

public boolean bindService(Intent service, ServiceConnection conn,
        int flags) {
    ...............
    return bindServiceCommon(service, conn, flags, mMainThread.getHandler(),
            Process.myUserHandle());
}

private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
        handler, UserHandle user) {
    IServiceConnection sd;
    ...............
    if (mPackageInfo != null) {
        //得到ServiceConnetion的Binder通信端
        sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
    } else {
        ................
    }

    //与Unbounded Service一样,检查Intent是否符合要求
    validateServiceIntent(service);

    try {
        ..........
        //调用AMS的bindService接口
        //ServiceConnection对应的Binder通信服务端将注册到AMS
        int res = ActivityManagerNative.getDefault().bindService(
                mMainThread.getApplicationThread(), getActivityToken(), service,
                service.resolveTypeIfNeeded(getContentResolver()),
                sd, flags, getOpPackageName(), user.getIdentifier());
        .................
    } catch (RemoteException e) {
        ...........
    }
}

从上面的代码可以看出,bindServiceCommon会将请求bindService的请求发送给AMS处理。
不过,在分析AMS中的bindService前,我们不妨先看看LoadedApk中的getServiceDispatcher函数:

public final IServiceConnection getServiceDispatcher(ServiceConnection c,
        Context context, Handler handler, int flags) {
    synchronized (mServices) {
        LoadedApk.ServiceDispatcher sd = null;      
        ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);
        if (map != null) {
            sd = map.get(c);
        }
        if (sd == null) {
            //初始时,需要创建ServiceConnection对应的ServiceDispatcher
            sd = new ServiceDispatcher(c, context, handler, flags);
            if (map == null) {
                map = new ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>();

                //然后将ServiceDispatcher加入到mServices中
                //前面分析Unbounded Service的结束流程时已经提到过
                //Bounded Service结束时,ContextImpl中的scheduleFinalCleanup函数
                //就会清理mServices中的信息
                mServices.put(context, map);
            }
            map.put(c, sd);
        } else {
            //检查参数的有效性
            sd.validate(context, handler);
        }

        //返回LoadedApk.ServiceDispatcher.InnerConnection
        return sd.getIServiceConnection();
    }
}

客户端调用bindService时,需要传入自定义的ServiceConnection。
从上面的代码可以看出,getServiceDispatcher函数将为初次使用的ServiceConnection创建ServiceDispatcher,
同时返回其对应的InnerConnection。

如下面的代码所示,InnerConnection继承IServiceConnection.Stub,将作为Binder通信的服务端,供AMS回调。

private static class InnerConnection extends IServiceConnection.Stub {
    ..................
}

2 AMS中的bindService
接下来,我们看看AMS的bindService函数:

public int bindService(IApplicationThread caller, IBinder token, Intent service,
        String resolvedType, IServiceConnection connection, int flags, String callingPackage,
        int userId) throws TransactionTooLargeException {
    //参数有效性检查
    ...............
    synchronized(this) {
        //调用ActiveServices的接口
        return mServices.bindServiceLocked(caller, token, service,
                resolvedType, connection, flags, callingPackage, userId);
    }
}

AMS的bindService函数进行一些参数检查后,就将工作递交给了ActiveServices的bindServiceLocked函数。
bindServiceLocked函数较长,我们分段进行分析。

2.1 bindServiceLocked Part-I

 int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
         String resolvedType, final IServiceConnection connection, int flags,
         String callingPackage, final int userId) throws TransactionTooLargeException {
    .................
    //得到客户端进程信息
    final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
    .............
    ActivityRecord activity = null;
    //如果是一个Activity绑定Service, 那么该Activity必须是有效的
    if (token != null) {
        //判断Activity是否存在于Task中
        activity = ActivityRecord.isInStackLocked(token);
        ..................
        if (activity == null) {
            //activity无效时,无法绑定
            ......
            return 0;
        }
    }

    //一些特殊标志位的处理
    .................

    //判断调用方是否来自前台
    final boolean callerFg = callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND;

    //BIND_EXTERNAL_SERVICE,使外部的isolated service使用本App的package name和userId
    //之前启动Ubounded Service时,也介绍过这种特殊的Service
    final boolean isBindExternal = (flags & Context.BIND_EXTERNAL_SERVICE) != 0;

    //与startService的流程一样,检索待启动的服务
    ServiceLookupResult res =
            retrieveServiceLocked(service, resolvedType, callingPackage, Binder.getCallingPid(),
                    Binder.getCallingUid(), userId, true, callerFg, isBindExternal);
    ...............
    ServiceRecord s = res.record;

    //特殊情况的权限检查
    ...............

bindServiceLocked的第一阶段,主要是进行一些条件检查、根据参数初始化一些变量,
然后利用retrieveServiceLocked函数检索出待启动服务对应的ServiceRecord。

2.2 bindServiceLocked Part-II

    try {
        //从待重启服务中,移除当前的Service
        if (unscheduleServiceRestartLocked(s, callerApp.info.uid, false)) {
            .............
        }

        if ((flags&Context.BIND_AUTO_CREATE) != 0) {
            s.lastActivity = SystemClock.uptimeMillis();
            //Service初次被绑定时,更改其状态信息
            if (!s.hasAutoCreateConnections()) {
                // This is the first binding, let the tracker know.
                ServiceState stracker = s.getTracker();

                if (stracker != null) {
                    stracker.setBound(true, mAm.mProcessStats.getMemFactorLocked(),
                            s.lastActivity);
                }
            }
        }
        ...............
        //将绑定的发起方和接收方关联起来,同时保存在AMS定义的数据结构中
        mAm.startAssociationLocked(callerApp.uid, callerApp.processName, callerApp.curProcState,
                s.appInfo.uid, s.name, s.processName);

        //根据Intent信息,检索出对应的IntentBindRecord(记录Intent,能启动哪个Service)
        //进一步从IntentBindRecord中检索出AppBindRecord (记录进程,与哪个Service绑定)
        //初次绑定时,将分别创建出IntentBindRecord和AppBindRecord
        AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);

        //构造注册connection对应的ConnectionRecord
        ConnectionRecord c = new ConnectionRecord(b, activity,
                connection, flags, clientLabel, clientIntent);

        //以下都是更新ServiceRecord中的数据结构
        IBinder binder = connection.asBinder();

        //ServiceRecord中按照Connection的Binder保存ConnectionRecord
        ArrayList<ConnectionRecord> clist = s.connections.get(binder);
        if (clist == null) {
            clist = new ArrayList<ConnectionRecord>();
            s.connections.put(binder, clist);
        }
        //新的ConnectionRecord保存到ServiceRecord和AppBinderRecord中
        clist.add(c);
        b.connections.add(c);

        if (activity != null) {
            if (activity.connections == null) {
                activity.connections = new HashSet<ConnectionRecord>();
            }
            //如果Activity是绑定的发起方,那么ActiivtyRecord中也会记录ConnectionRecord
            activity.connections.add(c);
        }

        //AppBinderRecord的client就是进程对应ProcessRecord
        b.client.connections.add(c);

bindServiceLocked的第二部分看起来比较繁琐,主要进行ConnectionRecord相关的一系列数据结构的更新。
这些数据结构的关系,大概如下图所示,这里的UML图并不严格,仅表示它们之间的关系:

大图链接

2.3 bindServiceLocked Part-III

        //一些特殊flag的处理
        ....................
        //如果Service所在进程之前已经启动过
        if (s.app != null) {
            //更新Service对应进程的优先级
            updateServiceClientActivitiesLocked(s.app, c, true);
        }
        .............
        //ActiveServices也将按照ServiceConnection的Binder保存ConnectionRecord
        clist = mServiceConnections.get(binder);
        //注意到同一个Binder可以对应多个ConnectionRecord
        //这是因为,客户端可以用同一个ServiceConnection绑定多个Service
        //每次绑定时,都会生成对应的ConnectionRecord,但这些ConnectionRecord共用相同的Binder
        if (clist == null) {
            clist = new ArrayList<ConnectionRecord>();
            mServiceConnections.put(binder, clist);
        }
        clist.add(c);

bindServiceLocked的第三部分,比较值得关注的是,更新Service所在进程优先级的函数updateServiceClientActivitiesLocked:

private boolean updateServiceClientActivitiesLocked(ProcessRecord proc,
        ConnectionRecord modCr, boolean updateLru) {
    if (modCr != null && modCr.binding.client != null) {
        if (modCr.binding.client.activities.size() <= 0) {
            // This connection is from a client without activities, so adding
            // and removing is not interesting.

            // Service被一个其它的有Activity的进程绑定时,才会改变其所在进程的优先级
            return false;
        }
    }

    boolean anyClientActivities = false;
    //轮寻进程中的每一个ServiceRecord
    for (int i=proc.services.size()-1; i>=0 && !anyClientActivities; i--) {
        ServiceRecord sr = proc.services.valueAt(i);

        //轮寻每个ServiceRecord对应的ConnectionRecord
        for (int conni=sr.connections.size()-1; conni>=0 && !anyClientActivities; conni--) {
            ArrayList<ConnectionRecord> clist = sr.connections.valueAt(conni);

            //轮寻每一个ConnectionRecord
            for (int cri=clist.size()-1; cri>=0; cri--) {
                ConnectionRecord cr = clist.get(cri);

                //Connection所在进程不存在,或与ServiceRecord在同一进程,continue
                if (cr.binding.client == null || cr.binding.client == proc) {
                    // Binding to ourself is not interesting.
                    continue;
                }

                //所在进程的Activity数量大于0,break
                if (cr.binding.client.activities.size() > 0) {
                    anyClientActivities = true;
                    break;
                }
            }
        }
    }

    if (anyClientActivities != proc.hasClientActivities) {
        proc.hasClientActivities = anyClientActivities;
        //参数中的updateLru为true
        if (updateLru) {
            //更新进程优先级
            mAm.updateLruProcessLocked(proc, anyClientActivities, null);
        }
        return true;
    }
    return false;
}

上面更新Service所在进程优先级的思路,从结果来看可以简化为:
如果当前Service所在进程,存在一个Service(一个进程内可以运行多个Service),
是由另一个含有Activity的进程绑定时(不论是否从Activity绑定),就会更新当前Service所在进程的优先级。

2.4 bindServiceLocked Part-IV
bindServiceLocked的前三部分,都是一些琐碎的细节,实际上实际的工作还是由第4部分完成。

        if ((flags&Context.BIND_AUTO_CREATE) != 0) {
            ............
            //如同Unbounded Service,仍然调用bringUpServiceLocked函数启动Service
            //正常时,返回null
            if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
                permissionsReviewRequired) != null) {
                return 0;
            }
        }

从代码可以看出,启动Servic仍是依靠bringUpServiceLocked函数。
bringUpServiceLocked函数中大部分的流程与Unbouned Service启动相似,只是在realStartServiceLocked函数中,
在回调Service的onCreate接口之后,回调Service的onStartCommand函数之前,需要执行requestServiceBindingsLocked函数:

private final void requestServiceBindingsLocked(ServiceRecord r, boolean execInFg)
        throws TransactionTooLargeException {
    //前面介绍ConnectionRecord的数据结构时已经提到过
    //bindService时,新的ConnectionRecord将加入到ServiceRecord的bindings中
    //此处依次处理所有的绑定请求
    for (int i=r.bindings.size()-1; i>=0; i--) {
        IntentBindRecord ibr = r.bindings.valueAt(i);
        //只要一次绑定失败,立即break
        if (!requestServiceBindingLocked(r, ibr, execInFg, false)) {
            break;
        }
    }
}

我们跟进一下requestServiceBindingLocked函数:

private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
        boolean execInFg, boolean rebind) throws TransactionTooLargeException {
    if (r.app == null || r.app.thread == null) {
        // If service is not currently running, can't yet bind.
        return false;
    }

    //IntentBindRecord被处理过后,requested将被置为true
    //因此只有第一次处理的请求,和重新绑定时,才会处理
    //这就是,客户端第一次绑定Service时,onBind函数才会被回调的原因
    if ((!i.requested || rebind) && i.apps.size() > 0) {
        try {
            //前文已经介绍过,发送消息前记录ServiceRecord状态信息,判断ANR等
            bumpServiceExecutingLocked(r, execInFg, "bind");

            r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);

            //调用ApplicationThread的scheduleBindService函数
            r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
                     r.app.repProcState);

            if (!rebind) {
                 i.requested = true;
            }
            i.hasBound = true;
            i.doRebind = false;
        } catch (TransactionTooLargeException e) {
            ..........
            final boolean inDestroying = mDestroyingServices.contains(r);
            //通知AMS
            serviceDoneExecutingLocked(r, inDestroying, inDestroying);
            throw e;
        } catch (RemoteException e) {
            .......
            final boolean inDestroying = mDestroyingServices.contains(r);
            serviceDoneExecutingLocked(r, inDestroying, inDestroying);
            return false;
        }
    }
    return true;
}

ApplicationThread的scheduleBindService函数被调用后,将发送BIND_SERVICE消息,
触发ActivityThread的handleBindService进行处理:

private void handleBindService(BindServiceData data) {
    Service s = mServices.get(data.token);
    ...............
    if (s != null) {
        try {
            ............
            try {
                if (!data.rebind) {
                    //调用Service的onBind函数
                    IBinder binder = s.onBind(data.intent);

                    //调用AMS的publishService函数,发布服务
                    ActivityManagerNative.getDefault().publishService(
                            data.token, data.intent, binder);
                } else {
                    s.onRebind(data.intent);
                    ActivityManagerNative.getDefault().serviceDoneExecuting(
                            data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
                }
                ensureJitEnabled();
            } catch(RemoteException ex) {
                ..........
            }
        } catch (Exception e) {
            ...........
        }
    }
}

从上面的代码可以看出,handleBindService调用Service的onBind函数后,将调用AMS的publishService函数发布该服务:

public void publishService(IBinder token, Intent intent, IBinder service) {
    //检查参数的有效性
    ..........
    synchronized(this) {
        .......
        //调用ActiveServices的publishServiceLocked
        mServices.publishServiceLocked((ServiceRecord)token, intent, service);
    }
}

跟进ActiveServices的publishServiceLocked函数:

void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
    .........
    try {
        .......
        if (r != null) {
            Intent.FilterComparison filter
                    = new Intent.FilterComparison(intent);
            IntentBindRecord b = r.bindings.get(filter);

            if (b != null && !b.received) {
                //Service返回的Binder保存到IntentBinderRecord中
                //这样下次调用bindService时,就可以直接从IntentBinderRecord中返回Service的Binder对象了
                //毕竟从上述流程也可以看出,只有第一次Bind Service时才会调用Service的onBind接口
                b.binder = service;
                b.requested = true;
                b.received = true;

                //轮寻找出需要回调的ServiceConnection
                for (int conni=r.connections.size()-1; conni>=0; conni--) {
                    ArrayList<ConnectionRecord> clist = r.connections.valueAt(conni);
                    for (int i=0; i<clist.size(); i++) {
                        ConnectionRecord c = clist.get(i);
                        //多个客户端以相同的Intent绑定服务时,均会回调
                        if (!filter.equals(c.binding.intent.intent)) {
                            .....................
                        }

                        try {
                            //进行回调
                             c.conn.connected(r.name, service);
                        } catch (Exception e) {
                            .........
                        }
                    }
                }
            }
        }
        //进行扫尾工作
        serviceDoneExecutingLocked(r, mDestroyingServices.contains(r), false);
    } finally {
        .......
    }
}

至此,我们知道了第一次绑定Service时,ServiceConnection是如何被回调的。

2.5 bindServiceLocked Part-V
现在我们看看bindServiceLocked的最后一部分:

        .............
        //当Service已经启动过,并且以对应的Intent绑定过时
        //可直接进行回调,返回IntentBinderRecord中的binder对象
        if (s.app != null && b.intent.received) {
            // Service is already running, so we can immediately
            // publish the connection.
            try {
                //回调InnerConnection的connected
                c.conn.connected(s.name, b.intent.binder);
            } catch(Exception e) {
                ............
            }

            // 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.
            //处理重新绑定的情况
            if (b.intent.apps.size() == 1 && b.intent.doRebind) {
                requestServiceBindingLocked(s, b.intent, callerFg, true);
            } 
        } else if (!b.intent.requested) {
            //冗余性代码,正常情况下,b.intent.requested执行到这个位置应该为true
            //为了容错,再次调用requestServiceBindingLocked函数进行绑定
            requestServiceBindingLocked(s, b.intent, callerFg, false);
        }
        ..............
    } finally {
        ........
    }

    return 1;
}

至此,客户端与Service绑定相关的工作结束,可以看看对应的回调流程。

3 InnerConnection中的bindService
前文中已经提到过,客户端注册到AMS的Binder通信服务端,实际上是LoadedApk的内部类ServiceDispatcher中的InnerConnection。
因此客户端与Service绑定成功后,AMS回调的是InnerConnection中的connected函数:

public void connected(ComponentName name, IBinder service) throws RemoteException {
    LoadedApk.ServiceDispatcher sd = mDispatcher.get();
    if (sd != null) {
        //调用ServiceDispatcher的connected函数
        sd.connected(name, service);
    }
}

可以看出InnerConnection仅作为一个通信接口,直接将工作递交给ServiceDispatcher处理。
我们跟进ServiceDispatcher,看看它的connected函数:

public void connected(ComponentName name, IBinder service) {
    if (mActivityThread != null) {
        //第三个参数表示command的类型,此时为0
        mActivityThread.post(new RunConnection(name, service, 0));
    } else {
        doConnected(name, service);
    }
}

RunConnection为ServiceDispatcher定义的内部类,我们看看它的run函数:

public void run() {
    if (mCommand == 0) {
        //最终调用ServiceDispatcher中的doConnected函数
        doConnected(mName, mService);
    } else if (mCommand == 1) {
        doDeath(mName, mService);
    }
}

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

    synchronized (this) {
        ..........
        old = mActiveConnections.get(name);
        //之前已经回调过,不再继续处理
        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.
            //创建一个ConnectionInfo
            info = new ConnectionInfo();
            info.binder = service;
            info.deathMonitor = new DeathMonitor(name, service);
            try {
                //监听Service死亡信息
                service.linkToDeath(info.deathMonitor, 0);

                //按组建名保存ConnectionInfo
                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);
        }

        if (old != null) {
            old.binder.unlinkToDeath(old.deathMonitor, 0);
        }
    }

    // If there was an old service, it is not disconnected.
    if (old != null) {
        //如果存在旧的连接,回调ServiceConnection的onServiceDisconnected函数
        mConnection.onServiceDisconnected(name);
    }
    // If there is a new service, it is now connected.
    if (service != null) {
        //回调ServiceConnection的onServiceConnected函数
        mConnection.onServiceConnected(name, service);
    }
}

从以上ServiceDispatcher的逻辑来看,客户端可以用同一个ServiceConnection绑定多个Service,
绑定成功后为每个Service创建对应的ConnectionInfo,并按Service组件名保存到mActiveConnections中。
因此,ServiceConnection回调接口的参数中,携带了ComponetName,用于指定连接或断开的具体Service。

至此,Bounded Service的启动流程分析完毕,整个流程可简化为下图:

大图链接

五、Bounded Service的结束流程
最后,我们来看看Bounded Service结束的流程。

1 ContextImpl的unbindService
我们从ContextImpl的unbindService开始分析整个流程:

//与该ServiceConnection绑定的所有Service解绑
public void unbindService(ServiceConnection conn) {
    ...........
    if (mPackageInfo != null) {
        //利用forgetServiceDispatcher函数,得到待解绑ServiceConnection的Binder服务端
        IServiceConnection sd = mPackageInfo.forgetServiceDispatcher(
                getOuterContext(), conn);
        try {
            //调用AMS的unbindService函数
            ActivityManagerNative.getDefault().unbindService(sd);
        } catch (RemoteException e) {
            ...........
        }
    } else {
        .............
    }
}

在分析AMS的unbindService前,我们先看看LoadedApk中的forgetServiceDispatcher函数:

public final IServiceConnection forgetServiceDispatcher(Context context,
        ServiceConnection c) {
    synchronized (mServices) {
        //根据客户端的Context,得到其map
        ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map
                = mServices.get(context);
        LoadedApk.ServiceDispatcher sd = null;
        if (map != null) {
            //根据ServiceConnection得到对应的ServiceDispatcher
            sd = map.get(c);
            if (sd != null) {
                //进行相关的清除操作
                map.remove(c);

                //调用ServiceDispatcher的doForget函数
                sd.doForget();
                if (map.size() == 0) {
                    mServices.remove(context);
                }

                ......
                //返回Binder服务端,即InnerConnection
                return sd.getIServiceConnection();
            }
        }
        ..............
    }
}

跟进一下ServiceDispatcher的doForget函数:

void doForget() {
    synchronized(this) {
        //清除mActiveConnections记录的所有ConnectionInfo信息
        for (int i=0; i<mActiveConnections.size(); i++) {
            ServiceDispatcher.ConnectionInfo ci = mActiveConnections.valueAt(i);
            ci.binder.unlinkToDeath(ci.deathMonitor, 0);
        }
        mActiveConnections.clear();
        mForgotten = true;
    }
}

从上面的代码可以看出,在将解绑请求发往AMS之前,客户端所在进程的LoadApk会先清除ServiceConnection相关的记录信息。

2 AMS的unbindService
接下来,我们看看AMS的unbindService函数:

public boolean unbindService(IServiceConnection connection) {
    synchronized (this) {
        //实际工作递交个ActiveServices处理
        return mServices.unbindServiceLocked(connection);
    }
}

跟进ActiveServices的unbindServiceLocked函数:

boolean unbindServiceLocked(IServiceConnection connection) {
    IBinder binder = connection.asBinder();
    ............
    //得到Connection对应的ConnectionRecord
    //这里其实也说明了,一个ServiceConnection(一个binder)可以绑定多个服务
    //每个Service有对应的ConnectionRecord
    ArrayList<ConnectionRecord> clist = mServiceConnections.get(binder);
    ...........
    try {
        while (clist.size() > 0) {
            ConnectionRecord r = clist.get(0);
            //进行清除操作
            removeConnectionLocked(r, null, null);
            ...................
        }
    } finally {
        ...........
    }
    return true;
}

从代码来看,ActiveServices的unbindServiceLocked函数,将利用removeConnectionLocked函数处理ServiceConnection对应的每一个ConnectionRecord。

3 ActiveServices的removeConnectionLocked
现在继续跟进removeConnectionLocked函数:

void removeConnectionLocked(
        ConnectionRecord c, ProcessRecord skipApp, ActivityRecord skipAct) {
    IBinder binder = c.conn.asBinder();
    AppBindRecord b = c.binding;
    ServiceRecord s = b.service;

    //与bindService添加数据结构信息对应,此时开始清理对应的数据结构
    ArrayList<ConnectionRecord> clist = s.connections.get(binder);
    if (clist != null) {
        clist.remove(c);
        if (clist.size() == 0) {
            s.connections.remove(binder);
        }
    }
    b.connections.remove(c);

    if (c.activity != null && c.activity != skipAct) {
        if (c.activity.connections != null) {
            c.activity.connections.remove(c);
        }
    }

    if (b.client != skipApp) {
        b.client.connections.remove(c);
        .............
        if (s.app != null) {
            //重新更新Service进程的优先级信息
            updateServiceClientActivitiesLocked(s.app, c, true);
        }
    }

    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.name);

    if (b.connections.size() == 0) {
        b.intent.apps.remove(b.client);
    }

    if (!c.serviceDead) {
        .............
        if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
            && b.intent.hasBound) {
            try {
                bumpServiceExecutingLocked(s, false, "unbind");
                ...................
                b.intent.hasBound = false;
                b.intent.doRebind = false;
                //调用ApplicationThread的scheduleUnbindService函数
                s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
            } catch (Exception e) {
                .............
            }
        }

        // If unbound while waiting to start, remove the pending service
        mPendingServices.remove(s);

        //如果是以BIND_AUTO_CREATE启动的服务
        if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
            boolean hasAutoCreate = s.hasAutoCreateConnections();
            .................
            //与Unbounded Service一样,调用bringDownServiceIfNeededLocked判断是否需要结束服务
            bringDownServiceIfNeededLocked(s, true, hasAutoCreate);
        }
    }
}

从上面的代码可以看出,ActiveServices的removeConnectionLocked函数,
主要用于清除ConnectionRecord对应的记录信息;
然后调用ApplicationThread的scheduleUnbindService函数;
最后与Unbounded Service一样,调用bringDownServiceIfNeededLocked函数,在必要是清理服务。
从上文的分析来看,Service被清理时,才会统一回调ServiceConnection的onServiceDisconnected函数。

4 ApplicationThread的scheduleUnbindService
ApplicationThread的scheduleUnbindService函数被调用时,将发送UNBIND_SERVICE,触发ActivityThread调用handleUnbindService:

private void handleUnbindService(BindServiceData data) {
    //根据token找出解绑的Service
    Service s = mServices.get(data.token);

    if (s != null) {
        try {
            .........
            //回调Service的onUnbind函数
            //一般返回false
            boolean doRebind = s.onUnbind(data.intent);
            try {
                if (doRebind) {
                    ActivityManagerNative.getDefault().unbindFinished(
                            data.token, data.intent, doRebind);
                } else {
                    //通知AMS unBind请求处理完毕
                    ActivityManagerNative.getDefault().serviceDoneExecuting(
                            data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
                }
            } catch (RemoteException ex) {
                ..........
            }
        } catch (Exception e) {
            ............
        }
    }
}

至此,Bounded Service结束流程分析完毕,对应的流程图可简化为下图:

大图链接

六、总结
本篇博客从Service的基础知识入手,记录了Service的基本用法和注意事项。
对于APK开发而言,掌握这一部分足以解决一般的问题。
后面主要分析了Android N中,Service启动和结束相关的流程。
通过分析源码流程,可以明白Service的一些技术细节,明白Service相关特性的原因。

作者:Gaugamela 发表于2016/12/23 15:35:29 原文链接
阅读:93 评论:0 查看评论

Viewing all articles
Browse latest Browse all 5930

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>