Service启动流程

文中的源代码版本为api23

Service启动流程

启动Service的方式有两种:startServicebindService

startService

先祭上一张流程图看个大概

此图省略了一些进程间通信的细节,同时假设 Service进程已经启动

Context.startService会经历以下调用链 Context.startService-> ContextImpl.startService-> ContextImpl.startServiceCommon

ContextImpl.startServiceCommon
private ComponentName startServiceCommon(Intent service, UserHandle user) {
    try {
        //做一些校验,如Android L版本及以上不允许隐式Intent启动Service
        validateServiceIntent(service);
        service.prepareToLeaveProcess();
        
        //调用AMS的startService
        ComponentName cn = ActivityManagerNative.getDefault().startService(
            mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
                        getContentResolver()), getOpPackageName(), user.getIdentifier());
        if (cn != null) {
            //一些异常判断
        }
        return cn;
    } catch (RemoteException e) {
        throw new RuntimeException("Failure from system", e);
    }
}
复制代码

该方法最核心的作用是将启动Service的请求通过IPC发送给了AMS

AMS接收到请求之后会经历以下方法调用 ActivityManagerService.startService-> ActiveService.startServiceLocked

ActiveService.startServiceLocked
ComponentName startServiceLocked(IApplicationThread caller, Intent service,
                                     String resolvedType,//mimetype
            int callingPid, int callingUid, String callingPackage, int userId)
            throws TransactionTooLargeException {
    //...
    //记录启动Service的进程是否处于前台
    final boolean callerFg;
    if (caller != null) {
        final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
        if (callerApp == null) {
            //...
        }
        callerFg = callerApp.setSchedGroup != Process.THREAD_GROUP_BG_NONINTERACTIVE;
    } else {
        callerFg = true;
    }


    //根据Intent信息查找ServiceLookupResult
    //ServiceLookupResult由ServiceRecord以及Service对应的permisson组成
    ServiceLookupResult res =
        retrieveServiceLocked(service, resolvedType, callingPackage,
                callingPid, callingUid, userId, true, callerFg);
    //...
    r.lastActivity = SystemClock.uptimeMillis();
    r.startRequested = true;
    r.delayedStop = false;
    //保存请求数据,服务启动之后会遍历pendingStarts,取出StartItem
    //拿里面的数据触发Service.onStartCommand
    r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
            service, neededGrants));

    //ServiceMap与userId一一对应,保存服务信息
    final ServiceMap smap = getServiceMap(r.userId);
    //是否添加到服务启动列表中
    //只有是后台进程发起调用,且目标进程未启动或者state>=PROCESS_STATE_SERVICE
    //才为true
    boolean addToStarting = false;
    //延迟启动的判断
    if (!callerFg//调用方处于后台,可能会延迟启动Service
            && r.app == null //ServiceRecord未被分配进程
            && mAm.mStartedUsers.get(r.userId) != null) {
        //获取应用进程实例
        ProcessRecord proc = mAm.getProcessRecordLocked(r.processName, r.appInfo.uid, false);
        if (proc == null || proc.curProcState > ActivityManager.PROCESS_STATE_RECEIVER) {
            //...
            if (r.delayed) {
                // This service is already scheduled for a delayed start; just leave
                // it still waiting.
                if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "Continuing to delay: " + r);
                return r.name;
            }
            if (smap.mStartingBackground.size() >= mMaxStartingBackground) {
                // Something else is starting, delay!
                Slog.i(TAG_SERVICE, "Delaying start of: " + r);
                smap.mDelayedStartList.add(r);
                r.delayed = true;
                return r.name;
            }
            if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "Not delaying: " + r);
            addToStarting = true;
        } else if (proc.curProcState >= ActivityManager.PROCESS_STATE_SERVICE) {
            addToStarting = true;
            //...
        } else if (DEBUG_DELAYED_STARTS) {
            //debug信息
        }
    } else if (DEBUG_DELAYED_STARTS) {
        //debug信息
    }

    return startServiceInnerLocked(smap, service, r, callerFg, addToStarting);

复制代码

ServiceMap这个结构用于保存用户当前运行的服务信息,retrieveServiceLocked方法逻辑就是通过IntentServiceMap中查找Service,如果当前服务还未启动,那么会创建一个ServiceRecord对象,保存在ServiceMap中。 还有一个需要注意的点是后台服务以及延迟启动机制,所有的后台服务都会被添加至一个名为mStartingBackground的列表中(添加逻辑在startServiceInnerLocked方法中),如果当前后台服务超过阈值,那么服务将会被添加至延迟启动列表中。

ActiveService.startServiceInnerLocked
ComponentName startServiceInnerLocked(ServiceMap smap, Intent service,
        ServiceRecord r,
        boolean callerFg,//服务启动者是否是前台进程
        boolean addToStarting) //是否添加到后台服务列表中
        throws TransactionTooLargeException {
    //...
    String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false);
    if (error != null) {
        return new ComponentName("!!", error);
    }
    
    //将服务添加至后台服务列表中
    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来进行后续的服务启动功能,同时会判断addToStarting值决定是否将服务添加至后台服务列表中。

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

    //服务进程已经启动,且服务也已启动,分发onStartCommand事件
    if (r.app != null && r.app.thread != null) {
        sendServiceArgsLocked(r, execInFg, false);
        return null;
    }

    //...

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

    //应用进程已经启动,调用realStartServiceLocked,返回
    if (!isolated) {
        app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
        if (DEBUG_MU) Slog.v(TAG_MU, "bringUpServiceLocked: appInfo.uid=" + r.appInfo.uid
                    + " app=" + app);
        if (app != null && app.thread != null) {
            try {
                app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
                realStartServiceLocked(r, app, execInFg);
                return null;
            } catch (TransactionTooLargeException e) {
                throw e;
            } catch (RemoteException e) {
                Slog.w(TAG, "Exception when starting service " + r.shortName, e);
            }

            // If a dead object exception was thrown -- fall through to
            // restart the application.
        }
    } else {
        app = r.isolatedProc;
    }
   
    //启动服务进程
    if (app == null) {
        if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
                "service", r.name, false, isolated, false)) == null) {
            String msg = "Unable to launch app "
                    + r.appInfo.packageName + "/"
                    + r.appInfo.uid + " for service "
                    + r.intent.getIntent() + ": process is bad";
            Slog.w(TAG, msg);
            bringDownServiceLocked(r);
            return msg;
        }
        if (isolated) {
            r.isolatedProc = app;
        }
    }

    //进程启动需要时间,先将服务保存起来
    if (!mPendingServices.contains(r)) {
        mPendingServices.add(r);
    }

    //...

    return null;
}
复制代码

这个方法根据服务进程的状态以及服务的状态产生了几个分支

  1. 如果服务进程已经启动,且服务也已经启动,那么调用sendServiceArgsLocked方法触发Service.onStartCommand
  2. 如果服务还未启动,且不是以isotate模式启动,那么调用ActivityManagerService.getProcessRecordLocked查找是否有可用进程,如果有就调用realStartServiceLocked启动服务
  3. 服务未启动,且服务的进程也没启动,那么调用ActivityManagerService.startProcessLocked启动进程,同时将服务保存至待启动列表中,等待进程启动完毕之后继续下面的流程。

sendServiceArgsLocked这个方法在realStartServiceLocked中也会被调用,我们到时候再分析。

关于进程启动,大家可以参考其他文章,这里不去展开讲。 进程启动之后,最终还是会进入到realStartServiceLocked方法中,方法调用链如下 ActivityThread.main-> ActivityThread.attach-> ActivityManagerService.attachApplication-> ActivityManagerService.attachApplicationLocked-> ActiveService.attachApplicationLocked-> ActiveService.realStartServiceLocked

下面我们就来分析一下ActiveService.realStartServiceLocked

ActiveService.realStartServiceLocked
private final void realStartServiceLocked(ServiceRecord r,
            ProcessRecord app, boolean execInFg) throws RemoteException {
    //...
    boolean created = false;
    try {
        //...
        app.thread.scheduleCreateService(r, r.serviceInfo,
                mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
                app.repProcState);
        r.postNotification();
        created = true;
    } catch (DeadObjectException e) {
        //...
    } finally {
        //...
    }

    //step2
    requestServiceBindingsLocked(r, execInFg);

    //...

    //step3
    sendServiceArgsLocked(r, execInFg, true);

    //...
}
复制代码

这个方法我做了很多精简,我们只关注一些最核心的部分

  1. 跨进程调用ApplicationThrad.scheduleCreateService方法,最终会走到ActivityThread.handleCreateService中,该方法通过反射创建一个Service的实例,并调用其onCreate方法,这部分的代码并不复杂,大家可以自行分析。
  2. 调用requestServiceBindingsLocked处理bindService请求,我们放到bindService启动流程去讲
  3. 调用sendServiceArgsLocked处理startService请求

下面我们分析一下sendServiceArgsLocked

ActiveService.sendServiceArgsLocked
private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
            boolean oomAdjusted) throws TransactionTooLargeException {
    final int N = r.pendingStarts.size();
    if (N == 0) {
        return;
    }

    while (r.pendingStarts.size() > 0) {
        Exception caughtException = null;
        ServiceRecord.StartItem si;
        try {
            si = r.pendingStarts.remove(0);
            //...
            si.deliveredTime = SystemClock.uptimeMillis();
            r.deliveredStarts.add(si);
            si.deliveryCount++;
            //...
            r.app.thread.scheduleServiceArgs(r, si.taskRemoved, si.id, flags, si.intent);
        } catch (TransactionTooLargeException e) {
           //...
        } catch (RemoteException e) {
            //...
        } catch (Exception e) {
            //...
        }

        //...
    }
}
复制代码

还记得pendingStarts么?在ActiveService.startServiceLocked方法中,ActiveService将启动服务的请求的信息保存在pendingStarts中。 sendServiceArgsLocked的逻辑非常简单,就是遍历pendingStarts,将所有的start请求发送出去。 发送的过程有涉及到了进程间通信,调用了ApplicationThrad.scheduleServiceArgs方法,该方法最终会进入到ActivityThread.handleServiceArgs中,触发Service.onStartCommand

至此,startService的流程就结束了。

bindService

bindService的大致流程如下

图中的流程是基于应用进程未启动的场景进行绘制的

Context.bindService会经历以下调用链 Context.bindService-> ContextImpl.bindService-> ContextImpl.bindServiceCommon

ContextImpl.bindServiceCommon
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
            UserHandle user) {
    IServiceConnection sd;
    if (conn == null) {
        throw new IllegalArgumentException("connection is null");
    }
    if (mPackageInfo != null) {
        //bindService成功之后会回调给ServiceConnection一个binder对象
        //用于后续的C/S通信,AMS直接通过IServiceConnection接口进行回调
        //由于ServiceConnection不是aidl接口,因此需要进行一定的包装
        sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(),
                mMainThread.getHandler(), flags);
    } else {
        throw new RuntimeException("Not supported in system context");
    }
    validateServiceIntent(service);
    try {
        //...
        service.prepareToLeaveProcess();
        int res = ActivityManagerNative.getDefault().bindService(
            mMainThread.getApplicationThread(), getActivityToken(), service,
            service.resolveTypeIfNeeded(getContentResolver()),
            sd, flags, getOpPackageName(), user.getIdentifier());
        if (res < 0) {
            //...
        }
        return res != 0;
    } catch (RemoteException e) {
        throw new RuntimeException("Failure from system", e);
    }
}
复制代码

bindServiceCommon的主要职责

  1. 调用LoadedApk.getServiceDispatcher是包装ServiceConnection成一个IServiceConnection对象,后续AMS可以直接通过该对象发布客户端与服务端进行通信的Binder对象。这个方法就不展开讲了。
  2. 跨进程调用ActivityManagerService.bindService方法继续服务启动流程

ActivityManagerService.bindService会直接调用ActiveService.bindServiceLocked

ActiveService.bindServiceLocked
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
            String resolvedType, IServiceConnection connection, int flags,
            String callingPackage, int userId) throws TransactionTooLargeException {
    //bind请求发起进程
    final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
    //...

    //请求发起进程是否处于前台
    final boolean callerFg = callerApp.setSchedGroup != Process.THREAD_GROUP_BG_NONINTERACTIVE;

    ServiceLookupResult res =
        retrieveServiceLocked(service, resolvedType, callingPackage,
                Binder.getCallingPid(), Binder.getCallingUid(), userId, true, callerFg);
    //...
    ServiceRecord s = res.record;

    final long origId = Binder.clearCallingIdentity();

    try {
        //...

        //下面这些操作是在AMS中建立起客户端和服务端的绑定关系
        //主要是保存客户端的一些信息到ServiceRecord中
        //保存服务端的一些信息到客户端(ActivityRecord、ProcessRecord)中
        
        //retrieveAppBindingLocked方法执行完毕之后会在ServiceRecord的bindings
        //字段中添加一条记录。bindings是Map类型,值类型为IntentBindRecord
        AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
        ConnectionRecord c = new ConnectionRecord(b, activity,
                connection, flags, clientLabel, clientIntent);

        IBinder binder = connection.asBinder();
        ArrayList<ConnectionRecord> clist = s.connections.get(binder);
        if (clist == null) {
            clist = new ArrayList<ConnectionRecord>();
            s.connections.put(binder, clist);
        }
        clist.add(c);
        b.connections.add(c);
        if (activity != null) {
            if (activity.connections == null) {
                activity.connections = new HashSet<ConnectionRecord>();
            }
            activity.connections.add(c);
        }
        b.client.connections.add(c);
        
        //...

        if ((flags&Context.BIND_AUTO_CREATE) != 0) {
            s.lastActivity = SystemClock.uptimeMillis();
            if (bringUpServiceLocked(s, service.getFlags(), callerFg, false) != null) {
                return 0;
            }
        }

        //...

        if (s.app != null && b.intent.received) {
            // Service is already running, so we can immediately
            // publish the connection.
            try {
                //conn就是客户端创建的IServiceConnection对象
                c.conn.connected(s.name, b.intent.binder);
            } catch (Exception e) {
                Slog.w(TAG, "Failure sending service " + s.shortName
                        + " to connection " + c.conn.asBinder()
                        + " (in " + c.binding.client.processName + ")", e);
            }

            //...
        } else if (!b.intent.requested) {
            requestServiceBindingLocked(s, b.intent, callerFg, false);
        }

        //...

    } finally {
        //...
    }

    return 1;
}
复制代码

该方法的核心有两点

  1. 调用bringUpServiceLocked启动服务
  2. 调用IServiceConnection.connected方法发布用于客户端与服务端进行通信的binder对象

看似简单,但是如果将BIND_AUTO_CREATE标志以及bringUpServiceLocked方法内部逻辑分支,场景会变得稍微复杂一些。这里我对各个场景下Service.onBindServiceConnection.onServiceConnected的调用时机做一下简单分析

设置BIND_AUTO_CREATE标志,服务未启动(包括进程未启动)

由于设置了BIND_AUTO_CREATE标志,接下来就会进入到bringUpServiceLocked中。该方法在分析startService流程的时候我们分析过。如果进程已经启动则会进入到realStartServiceLocked中,如果进程未启动,那么待进程启动之后通过进程间通信最终还是会走到realStartServiceLocked方法中。 realStartServiceLocked方法内会通过进程间通信,通知服务进程创建Service实例,并调用onCreate方法,之后会调用requestServiceBindingsLocked方法处理bind请求,这个方法之前特意留到这里进行分析。

ActiveService.requestServiceBindingsLocked
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;
        }
    }
}
复制代码

该方法很简单,遍历ServiceRecord.bindings的值,并挨个儿调用requestServiceBindingLocked

ActiveService.requestServiceBindingLocked
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;
}
复制代码

requestServiceBindingLocked也很简单,通过Binder通信,调用ApplicationThread.scheduleBindService方法,该方法在经过一些列调用之后,Service.onBind就会被调用。

ServiceConnection.onServiceConnected的回调则是在Service.onBind方法被调用之后。 ActivityThread在调完Service.onBind之后,会回调AMS,最终进入到ActiveService.publishServiceLocked

ActiveService.publishServiceLocked
void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
    final long origId = Binder.clearCallingIdentity();
    try {
        //...
        if (r != null) {
            Intent.FilterComparison filter
                    = new Intent.FilterComparison(intent);
            IntentBindRecord b = r.bindings.get(filter);
            if (b != null && !b.received) {
                //...
                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);
                        //...
                        try {
                            c.conn.connected(r.name, service);
                        } catch (Exception e) {
                            //...
                        }
                    }
                }
            }
            //...
        }
    } finally {
        Binder.restoreCallingIdentity(origId);
    }
}
复制代码

publishServiceLocked调用了IServiceConnection.connected,之后会经过进程间通信以及IServiceConnection实现类的内部逻辑,最终调用ServiceConnection.onServiceConnected方法。

case 2 : 设置BIND_AUTO_CREATE标志,服务已启动

此时bringUpServiceLocked会马上返回,继续bindServiceLocked的流程

ActiveService.bindServiceLocked
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
            String resolvedType, IServiceConnection connection, int flags,
            String callingPackage, int userId) throws TransactionTooLargeException {
    //...

    try {
        //...

        if (s.app != null && b.intent.received) {
            // Service is already running, so we can immediately
            // publish the connection.
            try {
                //conn就是客户端创建的IServiceConnection对象
                c.conn.connected(s.name, b.intent.binder);
            } catch (Exception e) {
                Slog.w(TAG, "Failure sending service " + s.shortName
                        + " to connection " + c.conn.asBinder()
                        + " (in " + c.binding.client.processName + ")", e);
            }

            //...
        } else if (!b.intent.requested) {
            requestServiceBindingLocked(s, b.intent, callerFg, false);
        }

        //...

    } finally {
        //...
    }

    return 1;
}
复制代码

这里要注意的有两个字段IntentBindRecord.requestedIntentBindRecord.received,它们会影响接下来的流程走向。

  • IntentBindRecord.requested 是否已经发起了Application.scheduleBindService调用,通知服务进程回调Service.onBind方法。
  • IntentBindRecord.received 该字段如果为true,说明Service.onBind方法已经被回调

而此时由于还没有调用ApplicationThread.scheduleBindService,因此receivedfalse,requested也是false,这时走requestServiceBindingLocked方法。 后续的流程,则跟case 1是一样的。

case 3 : 未设置BIND_AUTO_CREATE,服务已启动

如果未设置BIND_AUTO_CREATE,那么在bind流程中是不会调用bringUpServiceLocked启动服务的。而此时服务已经启动,那么可能是之前有调用过startService启动过服务。 此时receivedfalse,requested也是false,直接走requestServiceBindingLocked,跟case 2是一样的

case 4 : 未设置BIND_AUTO_CREATE,服务未启动

这种场景就需要等待服务启动了,服务启动的机制是下一次的startCommand被调用或者带有BIND_AUTO_CREATE标志的bindService被调用。无论进程是否启动,最终都会走到realStartServiceLocked,后续流程case 1一样。

至此,bindService的流程就分析完毕了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值