Service流程笔记

本文旨在记录一下自己学习 Android Service 源码时的笔记。

startService


首先看一下大致的流程图


Service流程笔记_第1张图片
Context.startService

上图中,AMS代表ActivityManagerService, AS代表ActiveServices。 这里假设Service的启动者(ProcessA)和 Service(ProcessB)不在同一个进程, 当然 startService 方式更多情况下还是用在自己进程内部。 这里只列出一些我认为比较主要的函数,忽略了异常情况下的处理, 例如延迟start, 找不到对应进程等。 图中颜色加深的几个关键方法:

1) AS.retrieveServiceLocked: 从PackageManager查询要启动的Service信息
2)AMS.checkAllowBackgroundLocked: 检查是否允许从后台启动Service
3)AS.bringUpServiceLocked: 对Service和Process的情况进行判度并处理,下面的那几个判断流程都是在该函数里
4)AMS.startProcessLocked: 启动Service对应的进程
5)AS.realStartServiceLocked: 使用IApplicationThread接口向Service进程发送create消息
6)AS.sendServiceArgsLocked: 使用IApplicationThread接口向Service进程发送start消息
7)Service.onStartCommand & Service.onCreate: Service callback


下面开始代码分析。
Context.startService
--> ContextImpl.startService
--> ContextImpl.startServiceCommon

前面经过Context和它的Wrapper模式下的调用栈, 进入ContextImpl.startServiceCommon

private ComponentName startServiceCommon(Intent service, UserHandle user) {
    try {
        //判断Intent中是否符合要求, Android L以上版本需要显示调用Service
        validateServiceIntent(service);

        //跨进程安全检查
        service.prepareToLeaveProcess(this);

        //调用AMS接口
        ComponentName cn = ActivityManagerNative.getDefault().startService(
            mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
                        getContentResolver()), getOpPackageName(), user.getIdentifier());
       ......
        }
        return cn;
    } catch (RemoteException e) {
        ......
    }
}

startServiceCommon会先做一些检查,其中 Intent.prepareToLeaveProcess对跨进程做安全性检查,例如在N以后的版本,在StrictMode下,不能使用scheme为"file://"的URI进行数据传输,必须使用FileProvider代替

public void prepareToLeaveProcess(boolean leavingPackage) {
        ......
        switch (mAction) {
        ......
            default:
                // N以上版本对scheme为"file://" 的URI需要用FileProvider代替
                mData.checkFileUriExposed("Intent.getData()");
        }
}

然后调用服务端 AMS.startService,在此我们省去 Binder 调用流程,直接进入ActivityManagerService

public ComponentName startService(IApplicationThread caller, Intent service,
        String resolvedType, String callingPackage, int userId)
        throws TransactionTooLargeException {
    ......
    synchronized(this) {
        ......
        ComponentName res = mServices.startServiceLocked(caller, service,
                resolvedType, callingPid, callingUid, callingPackage, userId);
        ......
        return res;
    }
}

AMS.startService先对参数检查, 然后调用ActiveServices.startServiceLocked

ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
        int callingPid, int callingUid, String callingPackage, final int userId)
        throws TransactionTooLargeException {
    ......

    // 1. 查询待启动Service的信息
    ServiceLookupResult res =
        retrieveServiceLocked(service, resolvedType, callingPackage,
                callingPid, callingUid, userId, true, callerFg, false);
    ......

    // 2. 检查是否可以在后台启动
    if (!r.startRequested) {
        try {
            final int allowed = mAm.checkAllowBackgroundLocked(
                    r.appInfo.uid, r.packageName, callingPid, true);
            if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
                ......
                return null;
            } finally {
                ......
            }
        } 
    }
    ......

    r.startRequested = true;
    ......
    //startService可以多次向Service传递信息,每次的信息都是一个StartItem,对应着一个StartId
    r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
            service, neededGrants));

    // 3. 下面的部分用于判断是否需要延迟启动Service
    final ServiceMap smap = getServiceMap(r.userId);

    // addToStarting值决定是否将待启动的Service加入后台启动队列ServiceMap.mStartingBackground
    // 这里只是判断, 它将被传入最后的startServiceInnerLocked, 在那里使用
    // 另外一个队列ServiceMap.mDelayedStartList则是延迟启动队列
    boolean addToStarting = false;
    if (!callerFg && r.app == null && mAm.mUserController.hasStartedUserState(r.userId)) {

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

        //若Service对应的进程未启动,或优先级过低,则需要将Service加入后台启动队列
        if (proc == null || proc.curProcState > ActivityManager.PROCESS_STATE_RECEIVER) {
        ......
            //若当前用户启动的后台服务数量已超上限,则延迟启动服务
            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);
}

startServiceLocked 做了一些前期准备:
1. 查询待启动Service的信息
2. 检查是否可以在后台启动
3. 检查是否需要延迟启动Service

这里第1步涉及到AMS对已启动Service信息的存储数据结构,我们在后面 AMS对Service的存储 里一起分析.
第2步, O 上有一些改动, 具体可以看后面 Background Service in Android O 部分.
第3步将判断待启动的Service是否需要在 Background start, 或者是 Delay start, 总体规则就是如果进程未启动或者优先级低,则 Background start, 如果连 Background start 队列都已满,则加入 Delay 队列。 这一部分的看的不是很明白,特别是两个队列的关系, 我本以为是两个优先级的队列,但是看后面的处理函数ServiceMap.rescheduleDelayedStarts,好像不是, 以后有机会再看看。

检查完成之后进入startServiceInnerLocked

ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
        boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
    ......
    String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);

    ......
    // 这里会根据前面传进来的addToStarting值处理延迟Service
    if (r.startRequested && addToStarting) {
        boolean first = smap.mStartingBackground.size() == 0;
        smap.mStartingBackground.add(r);
        r.startingBgTimeout = SystemClock.uptimeMillis() + BG_START_TIMEOUT;
       
        if (first) {
            smap.rescheduleDelayedStarts();
        }
    } else if (callerFg) {
        smap.ensureNotStartingBackground(r);
    }

    return r.name;
}

真正的工作在 bringUpServiceLocked 里

private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
        boolean whileRestarting, boolean permissionsReviewRequired)
        throws TransactionTooLargeException {
    ......
    // Case 1. 如果Service已经启动过,直接发送start
    if (r.app != null && r.app.thread != null) {
        sendServiceArgsLocked(r, execInFg, false);
        return null;
    }
    ......
    // Case 2. Service没启动过 
    // 真正启动之前再做一些检查并处理, 例如service是否还有delay标志,service所处的进程时否结束了
    ......

    final String procName = r.processName;
    ProcessRecord app;
    if (!isolated) {
        // 查询Service对应的进程信息
        app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
        if (app != null && app.thread != null) {
            try {
                ......
                // Case 2.1 查询到进程, 则直接start Service
                realStartServiceLocked(r, app, execInFg);
                return null;
            } 
            ......
        }
    } else {
       ......
    }
    
    // Case 2.2 查询不到进程,则需要先start Process
    if (app == null && !permissionsReviewRequired) {
        //真正启动进程
        if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
                "service", r.name, false, isolated, false)) == null) {
            ......
            // Case 2.2.1 进程启动失败, stop service
            bringDownServiceLocked(r);
            return msg;
        }
        ......
    }
    // Case 2.2.2 进程启动成功,把Service添加到mPendingServices中
    if (!mPendingServices.contains(r)) {
        mPendingServices.add(r);
    }

    return null;
}

bringUpServiceLocked 分几种情况处理:
1 如果Service已经启动过,调sendServiceArgsLocked发送start请求
2 如果Service还未启动过, 查询Serviced对应进程,看看进程是否已经启动
2.1 进程已启动, 调用realStartServiceLocked,创建Service
2.2 进程未启动, 调用AMS.startProcessLocked启动进程
2.2.1 进程启动失败, 调用bringDownServiceLocked结束Service
2.2.2 进程启动成功, 将Service信息保存到mPendingServices,等待后面进程回调对其进行处理

这里我们简单对2.2.2的情况说明一些,进程启动成功后会调用AMS.attachApplicationLocked,在这里将mPendingServices里属于该进程的Service启动,调用的也是realStartServiceLocked

boolean attachApplicationLocked(ProcessRecord proc, String processName)
        throws RemoteException {
        ......
            for (int i=0; i

也就是说2.1和2.2.2最后都是进入realStartServiceLocked

private final void realStartServiceLocked(ServiceRecord r,
        ProcessRecord app, boolean execInFg) throws RemoteException {

    ......
    try {
        ......
        // 发送create请求
        app.thread.scheduleCreateService(r, r.serviceInfo,
                mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
                app.repProcState);
        r.postNotification();
        created = true;
    } catch (DeadObjectException e) {
        ......
    } finally {
        ......
    }

    ......
    // 发送bind请求,对于startService,bind队列并没有增加
    // 所以在这种情况下requestServiceBindingsLocked相当于空函数
    // 后面分析bindService的时候我们再来看这个函数
    requestServiceBindingsLocked(r, execInFg);

    ......
    // 构造start参数StartItem
    if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
        r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
                null, null));
    }
    // 发送start请求,同前面bringUpServiceLocked的Case 1
    sendServiceArgsLocked(r, execInFg, true);

    ......
}

realStartServiceLocked是通知客户端创建和启动Service的地方
1 调用ApplicationThead.scheduleCreateService通知客户端创建服务
2 调用requestServiceBindingsLocked发送bind请求,使用于bindService情况
3 调用sendServiceArgsLocked发送start请求,使用于startService情况

这几个步骤最后其实都差不多,都是AMS通过ApplicationThread对应的接口通知ActivityThread,以第一种情况为例,省去Binder调用流程,大致如下:
ApplicationThread.scheduleCreateService
--> ActivityThread.H.handleMessage(CREATE_SERVICE)
--> ActivityThread.handleCreateService

private void handleCreateService(CreateServiceData data) {
    ......
    Service service = null;
    try {
        // 使用反射创建 Service 实例
        java.lang.ClassLoader cl = packageInfo.getClassLoader();
        service = (Service) cl.loadClass(data.info.name).newInstance();
    } catch (Exception e) {
        ......
    }

    try {
        ......
        // 调用onCreate回调,然后保存起来
        service.onCreate();
        mServices.put(data.token, service);
        //通知AMS创建完成
        try {
            ActivityManagerNative.getDefault().serviceDoneExecuting(
                    data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
        } catch (RemoteException e) {
            
        }
        ......
    } catch (Exception e) {
        ......
    }
}

ActivityThread.handleCreateService创建Service实例,调用onCreate,并保存Service.

sendServiceArgsLocked流程差不多,最后由ActivityThread.handleServiceArgs处理,调用onStartCommon

private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
        boolean oomAdjusted) throws TransactionTooLargeException {
    ......
    while (r.pendingStarts.size() > 0) {
        ServiceRecord.StartItem si = null;
        try {
            ......
            si = r.pendingStarts.remove(0);
            // 记录start次数
            si.deliveryCount++;

            int flags = 0;
            // 我们可以利用onStartCommand的flag参数来判断是否是第一次start
            if (si.deliveryCount > 1) {
                flags |= Service.START_FLAG_RETRY;
            }
            if (si.doneExecutingCount > 0) {
                flags |= Service.START_FLAG_REDELIVERY;
            }
            r.app.thread.scheduleServiceArgs(r, si.taskRemoved, si.id, flags, si.intent);
        } 
        ......
    }
}

private void handleServiceArgs(ServiceArgsData data) {
    // 前面onCreate的时候已经保存了Service在mServices里,现在可以取出
    Service s = mServices.get(data.token);
    if (s != null) {
        try {
            ......
            if (!data.taskRemoved) {
                res = s.onStartCommand(data.args, data.flags, data.startId);
            } else {
                ......
            }
            ......
        } catch (Exception e) {
            ......
        }
    }
}

至此Context.startService完成

bindService


bindService流程同startService差不多,主要多了两个点, 一个是AMS除了要保存Service信息,还要保存caller app和ServiceConnection信息(用于交互), 这个由ServiceRecord.retrieveAppBindingLocked负责; 另外就是bind完成要使用IActivityManager.publishService接口通知AMS,从而让ServiceConnection.onServiceConnected执行

Service流程笔记_第2张图片
Context.bindService

下面开始看代码
Context.bindService
--> ContextImpl.bindServiceCommon
--> AMS.bindService
--> AS.bindServiceLocked

前面的跟startService的差不多, 进入AS.bindServiceLocked

int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
        String resolvedType, final IServiceConnection connection, int flags,
        String callingPackage, final int userId) throws TransactionTooLargeException {
    ......
    // 从ServiceMap查找ServiceRecord
    ServiceLookupResult res =
        retrieveServiceLocked(service, resolvedType, callingPackage, Binder.getCallingPid(),
                Binder.getCallingUid(), userId, true, callerFg, isBindExternal);
    ServiceRecord s = res.record;
    ......
    try {
        ......
        // 从ServiceRecord查找Client应用信息
        AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
        // 构造ServiceConnection信息
        ConnectionRecord c = new ConnectionRecord(b, activity,
                connection, flags, clientLabel, clientIntent);
        ......
        // 将ServiceConnection保存
        IBinder binder = connection.asBinder();
        ArrayList clist = s.connections.get(binder);
        if (clist == null) {
            clist = new ArrayList();
            s.connections.put(binder, clist);
        }
        clist.add(c);
        b.connections.add(c);      
        
        clist = mServiceConnections.get(binder);
        if (clist == null) {
            clist = new ArrayList();
            mServiceConnections.put(binder, clist);
        }
        clist.add(c);

        if ((flags&Context.BIND_AUTO_CREATE) != 0) {
            ......
            // bringUpService会通知客户端onbind
            if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
                    permissionsReviewRequired) != null) {
                return 0;
            }
            ......
        }
        ......
    } finally {
        ......
    }
}

bindServiceLocked流程比较简单,先查找或者构造调用者app和ServiceConnection信息,存储于ServiceRecord, 然后调用bringUpServiceLocked.

bringUpServiceLocked包含了startService和bindService的逻辑,startService的部分前面已经分析过, 这里看bindSerivce有关的流程:
bringUpServiceLocked
--> realStartServiceLocked
--> requestServiceBindingsLocked

// 对ServiceRecord.bindings里的元素依次调用requestServiceBindingLocked
private final void requestServiceBindingsLocked(ServiceRecord r, boolean execInFg)
        throws TransactionTooLargeException {
    for (int i=r.bindings.size()-1; i>=0; i--) {
        IntentBindRecord ibr = r.bindings.valueAt(i);
        if (!requestServiceBindingLocked(r, ibr, execInFg, false)) {
            break;
        }
    }
}

private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
        boolean execInFg, boolean rebind) throws TransactionTooLargeException {
    ......
    if ((!i.requested || rebind) && i.apps.size() > 0) {
        try {
            ......
            r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
                    r.app.repProcState);
            ......
        } catch (TransactionTooLargeException e) {
            ......
        } catch (RemoteException e) {
            ......
        }
    }
    return true;
}

requestServiceBindingsLocked则通过Binder最后进入ActivityThread.handleBindService:
ApplicationThread.scheduleBindService
--> ActivityThread.H.handleMessage(BIND_SERVICE)
--> ActivityThread.handleBindService

private void handleBindService(BindServiceData data) {
    // 前面Service onCreate的时候已被保存在mServices
    Service s = mServices.get(data.token);
    ......
    if (s != null) {
            ......
            try {
                if (!data.rebind) {
                    // 执行onBind回调
                    IBinder binder = s.onBind(data.intent);
                    // 通知AMS bind完成
                    ActivityManagerNative.getDefault().publishService(
                            data.token, data.intent, binder);
                } else {
                   ......
                }
               .
            } catch (RemoteException ex) {
                ......
            }
        } catch (Exception e) {
           ......
        }
}

handleBindService执行Service.onBind,并将结果通过AMS.publishService发送给AMS
AMS.publishService
--> AS.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和状态
                b.binder = service;
                b.requested = true;
                b.received = true;
                // 找出所有符合的ServiceConnection执行onServiceConnected
                for (int conni=r.connections.size()-1; conni>=0; conni--) {
                    ArrayList clist = r.connections.valueAt(conni);
                    for (int i=0; i

publishService通知ServiceConnection执行onServiceConnected,至此bindService结束

AMS对Service的存储(stopService/unbindService)


AMS里把所有启动的Service存放在ActiveServices.mServiceMap, 这是一个SparseArray,可以看成一个Map,其key是调用者的userId,也就是说AMS将系统中所有启动过的Service按调用者的userId分组. 为了方便分析,这里简单的将userId等同于appId,即简单的等同于一个应用.

而ServiceMap本身是存储了两个Map mServicesByNamemServicesByIntent, 分别代表显式和隐式调用的Service信息

class ServiceMap extends Handler {
    final ArrayMap mServicesByName = new ArrayMap<>();
    final ArrayMap mServicesByIntent = new ArrayMap<>();
    ......
}

这里我们只取隐式的mServicesByIntent来分析,它的key是Intent.FilterComparison,可以把它看成是一个override了equals方法的Intent,我们选取最为常见的action作为Intent的代表,当然两个Intent是否相等还要由 Data, Category 等比较决定,但是不影响我们对这里数据结构的分析. 所以最终我们发现,其实AMS用组合(caller appId, action)作为key来存储已启动的Service.

我们假设 Music 应用有一个 PlaybackService, 注册的action有两个.


    
        
    
    
        
    

现在在Settings和Video两个应用分别startService,其中Settings有两处,用了两个不同的action启动

// In Settings process
startService(new Intent("com.haha.music.action.PLAYBACK1"));
...
startService(new Intent("com.haha.music.action.PLAYBACK2"));

// In Video process
startService(new Intent("com.haha.music.action.PLAYBACK1"));

最后内存里的情况如下:


Service流程笔记_第3张图片

了解了ServiceMap的结构之后,我们看startService/stopService时对Service的查找, 就是retrieveServiceLocked函数

private ServiceLookupResult retrieveServiceLocked(Intent service,
        String resolvedType, String callingPackage, int callingPid, int callingUid, int userId,
        boolean createIfNeeded, boolean callingFromFg, boolean isBindExternal) {
    ServiceRecord r = null;
    // 得到当前用户的userId
    userId = mAm.mUserController.handleIncomingUser(callingPid, callingUid, userId, false,
            ActivityManagerService.ALLOW_NON_FULL_IN_PROFILE, "service", null);
    // 从ServiceMap中查找
    ServiceMap smap = getServiceMap(userId);
    final ComponentName comp = service.getComponent();
    if (comp != null) {
        r = smap.mServicesByName.get(comp);
    }
    if (r == null && !isBindExternal) {
        Intent.FilterComparison filter = new Intent.FilterComparison(service);
        r = smap.mServicesByIntent.get(filter);
    }

    // 如果Map里找不到则要开始构造这个ServiceRecord并保存起来
    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);
            ServiceInfo sInfo = rInfo != null ? rInfo.serviceInfo : null;

            ComponentName name = new ComponentName(
                    sInfo.applicationInfo.packageName, sInfo.name);
            
            r = smap.mServicesByName.get(name);
            if (r == null && createIfNeeded) {
                ......
                r = new ServiceRecord(mAm, ss, name, filter, sInfo, callingFromFg, res);
                smap.mServicesByName.put(name, r);
                smap.mServicesByIntent.put(filter, r);
                ......
            }
        } catch (RemoteException ex) {
            ......
        }
    }
    if (r != null) {
        return new ServiceLookupResult(r, null);
    }
    return null;
}

AS.retrieveServiceLocked其实就是从mServiceMap里查找对应的ServiceRecord,如果找不到就构造一个. 到此,这里的数据对startService/stopService已经够用.

但是对bindService/unbindService, AMS还得记录Client和ServiceConnection,这个由ServiceRecord.bindingsServiceRecord.connections 来负责. 通过简化, 我们可以认为ServiceRecord.bindings用来存储调用者应用信息, key为action, value为caller app信息(AppBinderRecord)队列. ServiceRecord.connections存储ServiceConnection, key为ServiceConnection在AMS的代表(binder). 这部分逻辑主要在retrieveAppBindingLocked和bindServiceLocked

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

int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
        String resolvedType, final IServiceConnection connection, int flags,
        String callingPackage, final int userId) throws TransactionTooLargeException {
    ......
    try {
        ......
        // 从ServiceRecord查找Client应用信息
        AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
        // 构造ServiceConnection信息
        ConnectionRecord c = new ConnectionRecord(b, activity,
                connection, flags, clientLabel, clientIntent);
        ......
        // 将ServiceConnection保存在ServiceRecord.connections
        IBinder binder = connection.asBinder();
        ArrayList clist = s.connections.get(binder);
        if (clist == null) {
            clist = new ArrayList();
            s.connections.put(binder, clist);
        }
        clist.add(c);
        b.connections.add(c); 
     
        // 除了每个ServiceRecord保存着自己的connection队列
        // ActiveServices里还有一个所有connection的队列
        clist = mServiceConnections.get(binder);
        if (clist == null) {
            clist = new ArrayList();
            mServiceConnections.put(binder, clist);
        }
        clist.add(c);
        ......
    } finally {
        ......
    }
}

上面是属于Service/ServiceConnection/Caller app的创建和保存,位于startService/bindService.

下面我们看看它们的删除, 这个位于stopService和unbindService

private void stopServiceLocked(ServiceRecord service) {
    ......
    // 设置 startRequested 标志
    service.startRequested = false;
    ......
    // 注意这里的最后两个参数值,都是false
    bringDownServiceIfNeededLocked(service, false, false);
}

// unbindService调用流程:
// AMS.unbindService --> AS.unbindServiceLocked --> AS.removeConnectionLocked
void removeConnectionLocked(
    ConnectionRecord c, ProcessRecord skipApp, ActivityRecord skipAct) {
    ......
    AppBindRecord b = c.binding;

    ......
    // remove ServiceRecord.connectins里的记录
    ArrayList clist = s.connections.get(binder);
    if (clist != null) {
        clist.remove(c);
        if (clist.size() == 0) {
            s.connections.remove(binder);
        }
    }

    ......
    // remove ActiveServices.mServiceConnections里的记录
    clist = mServiceConnections.get(binder);
    if (clist != null) {
        clist.remove(c);
        if (clist.size() == 0) {
            mServiceConnections.remove(binder);
        }
    }

    if (!c.serviceDead) {
        ......
        // 调用onUnbind
        if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
                && b.intent.hasBound) {
            try {
                ......
                s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
            } catch (Exception e) {
                ......
            }
        }

        if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
            boolean hasAutoCreate = s.hasAutoCreateConnections();
            ......
            // 最后调用bringDownServiceIfNeededLocked, 注意这里最后两个参数
            // 第一个为true, 第二个为s.hasAutoCreateConnections()
            bringDownServiceIfNeededLocked(s, true, hasAutoCreate);
        }
    }
}

stopService相对比较简单,就是设置一下startRequested为false, 然后调用bringDownServiceIfNeededLocked, 注意这里传入的最后两个参数值,都是false

unbindService先找到要unbind的ServiceConnection, 调用removeConnectionLocked对其内部各种数据清理(主要是ServiceRecord.bindings, connections, ActiveServices.mServiceConnections), 然后使用ApplicationThread.scheduleUnbindService通知客户端onUnbind, 最后也是调用bringDownServiceIfNeededLocked, 注意这里传入的最后两个参数值,但是其传入的是true和s.hasAutoCreateConnections()

可以看到stop/unbind最终都会调用bringDownServiceIfNeededLocked

private final void bringDownServiceIfNeededLocked(ServiceRecord r, boolean knowConn,
        boolean hasConn) {

    if (isServiceNeeded(r, knowConn, hasConn)) {
        return;
    }
    ......
    bringDownServiceLocked(r);
}

如果isServiceNeeded返回false就会执行bringDownServiceLocked,先看一下这个函数

private final void bringDownServiceLocked(ServiceRecord r) {
    ......

    final ServiceMap smap = getServiceMap(r.userId);
    smap.mServicesByName.remove(r.name);
    smap.mServicesByIntent.remove(r.intent);
    
    ......
    if (r.app != null) {
        ......
        if (r.app.thread != null) {
            ......
            try {
                ......
                r.app.thread.scheduleStopService(r);
            } catch (Exception e) {
                ......
            }
        } else {
            ......
        }
    } else {
        ......
    } 
    ......
}

bringDownServiceLocked其实就是清理ActiveServices.mServiceMap里的数据,并且通知Service.onDestory

回过头看isServiceNeeded

private final boolean isServiceNeeded(ServiceRecord r, boolean knowConn, boolean hasConn) {
    // Are we still explicitly being asked to run?
    if (r.startRequested) {
        return true;
    }

    // Is someone still bound to us keepign us running?
    if (!knowConn) {
        hasConn = r.hasAutoCreateConnections();
    }
    if (hasConn) {
        return true;
    }

    return false;
}

//ServiceRecord.java
public boolean hasAutoCreateConnections() {
    for (int conni=connections.size()-1; conni>=0; conni--) {
        // unbindService --> removeConnectionLocked的时候会remove对应的connection
        // 所以剩下的还在connections中的就是还没unbind的
        ArrayList cr = connections.valueAt(conni);
        for (int i=0; i

结合上面stopService和unbindService调用时传给它的参数值, 我们知道isServiceNeeded的逻辑等同于r.startRequested && r.hasAutoCreateConnections()

r.startRequested在startService时置为true, stopService置为false, r.hasAutoCreateConnections()则在没有client bindService的时候返回false, 所以就是说bringDownServiceLocked,即Service.onDestory只有在调用过stopService(或者没调用过startService)和所有connection都被unbind之后才会被执行

Background Service in Android O


现在Android对 Background Task(Service/Broadcast等)的限制已经越来越严格, 对Service而言,当进程处于后台时, Android O 已经不允许 startService, 上面是N的代码,我们简单看下 O preview的流程

ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
        int callingPid, int callingUid, String callingPackage, final int userId)
        throws TransactionTooLargeException {
    ......
    if (!r.startRequested && !fgRequired) {
        final int allowed = mAm.getAppStartModeLocked(r.appInfo.uid, r.packageName,
                r.appInfo.targetSdkVersion, callingPid, false, false);
    }
    ......
}

startServiceLocked 关于对于Service是否允许后台start的判断在O上有了变化,这里使用的是AMS.getAppStartModeLocked

int getAppStartModeLocked(int uid, String packageName, int packageTargetSdk,
        int callingPid, boolean alwaysRestrict, boolean disabledOnly) {
    ......
    if (uidRec == null || alwaysRestrict || uidRec.idle) {
        ......
        if (ephemeral) {
            ......
        } else {
            ......
            //alwaysRestrict为false,所以调用appServicesRestrictedInBackgroundLocked
            final int startMode = (alwaysRestrict)
                    ? appRestrictedInBackgroundLocked(uid, packageName, packageTargetSdk)
                    : appServicesRestrictedInBackgroundLocked(uid, packageName,
                            packageTargetSdk);
            
            //当Service的startMode不是Normal
            if (startMode == ActivityManager.APP_START_MODE_DELAYED) {
                    ......
                    if (proc != null &&
                            //并且进程不是处于后台
                            !ActivityManager.isProcStateBackground(proc.curProcState)) {
                        //那么就把startMode改为Normal
                        return ActivityManager.APP_START_MODE_NORMAL;
                    }
            }
            //否则返回原模式
            return startMode;
        }
    }
    ......
}

这里fgRequired参数在Context.startService时为false, 而Context.startForegroundService为true, 所以这里调用的是appRestrictedInBackgroundLocked

// 处于 Persistent/background whitelist/device idle white list 这三种情况下的 app 不受 background 限制 
int appServicesRestrictedInBackgroundLocked(int uid, String packageName, int packageTargetSdk) {
    // Persistent app?
    if (mPackageManagerInt.isPackagePersistent(packageName)) {
        return ActivityManager.APP_START_MODE_NORMAL;
    }

    // Non-persistent but background whitelisted?
    if (uidOnBackgroundWhitelist(uid)) {
        return ActivityManager.APP_START_MODE_NORMAL;
    }

    // Is this app on the battery whitelist?
    if (isOnDeviceIdleWhitelistLocked(uid)) {
        return ActivityManager.APP_START_MODE_NORMAL;
    }

    // None of the service-policy criteria apply, so we apply the common criteria
    return appRestrictedInBackgroundLocked(uid, packageName, packageTargetSdk);
}

int appRestrictedInBackgroundLocked(int uid, String packageName, int packageTargetSdk) {
    // Apps that target O+ are always subject to background check
    if (packageTargetSdk >= Build.VERSION_CODES.O) {
        return ActivityManager.APP_START_MODE_DELAYED_RIGID;
    }
    ......
}

appRestrictedInBackgroundLocked对处于Persistent/background whitelist/device idle white list下的apps不设置Background limit,而其他的当targetSdkVersion >= O时, 则会限制

在Developer Guide的Background Execution Limits文章中, Google 建议是用 JobScheduler 来取代 Background task. 另外目前 Android O preview 版本还提供了 Context.startForegroundService, 按照其说法调用该接口创建Service后,需要在5秒(ANR interval)内调用 Service.startForeground(),否则 Service 就会被 stop 并且应用进程将 ANR.

目前 Android O 处于 preview 阶段,不知道后续还会不会出现变化,因为看网上有一些文章提到 NotificationManager.startServiceInForeground(), 但是官网上已经找不到该接口了

你可能感兴趣的:(Service流程笔记)