美文网首页
Service启动流程

Service启动流程

作者: gczxbb | 来源:发表于2019-01-28 23:39 被阅读3次

    前面的文章分析过Activity组件的启动流程,Service是四大组件之一,一种后台服务,它一般没有界面,我们感知不到它的存在。在Android开发时一种重要的组件,在主线程中运行,本文分析一下Service的启动流程,通常是以下代码启动一个Service。

    Intent intent = new Intent(this, XxxService);
    startService(intent);
    

    Activty中的startService方法,调用父类ContextWrapper的startService方法。

    @Override
    public ComponentName startService(Intent service) {
        return mBase.startService(service);
    }
    

    在ContextWrapper中,mBase是ContextImpl的具体实现类,下面是它的startService方法。

    @Override
    public ComponentName startService(Intent service) {
        warnIfCallingFromSystemProcess();
        return startServiceCommon(service, mUser);
    }
    

    调用startServiceCommon方法。

    private ComponentName startServiceCommon(Intent service, UserHandle user) {
        try {
            ...
            ComponentName cn = ActivityManagerNative.getDefault().startService(
                    mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
                            getContentResolver()), getOpPackageName(), user.getIdentifier());
            ...
            return cn;
        } catch (RemoteException e) {
        }
    }
    

    访问Ams服务,调用ActivityManagerService的#startService方法。

    @Override
    public ComponentName startService(IApplicationThread caller, Intent service,
            String resolvedType, String callingPackage, int userId)
            throws TransactionTooLargeException {
        //service和callingPackage必须存在。否则抛异常。
        synchronized(this) {
            final int callingPid = Binder.getCallingPid();
            final int callingUid = Binder.getCallingUid();
            final long origId = Binder.clearCallingIdentity();
            ComponentName res = mServices.startServiceLocked(caller, service,
                    resolvedType, callingPid, callingUid, callingPackage, userId);
            Binder.restoreCallingIdentity(origId);
            return res;
        }
    }
    

    参数ApplicationThread,App回调,将启动的Service类Intent,resolveType。调用ActiveServices的startServiceLocked方法,Ams类将Service启动的相关流程委托给ActiveServices类管理。

    ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
            int callingPid, int callingUid, String callingPackage, int userId)
            throws TransactionTooLargeException {
        final boolean callerFg;
        if (caller != null) {
            //根据IApplicationThread获取ProcessRecord,callerApp空报异常。
            final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
            callerFg = callerApp.setSchedGroup != Process.THREAD_GROUP_BG_NONINTERACTIVE;
        } else {
            callerFg = true;
        }
        ServiceLookupResult res =
            retrieveServiceLocked(service, resolvedType, callingPackage,
                    callingPid, callingUid, userId, true, callerFg);
    
        ServiceRecord r = res.record;
        final ServiceMap smap = getServiceMap(r.userId);
        ...
        return startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
    }
    

    调用ActiveServices的startServiceInnerLocked方法。

    ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
            boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
        ProcessStats.ServiceState stracker = r.getTracker();
        if (stracker != null) {
            stracker.setStarted(true, mAm.mProcessStats.getMemFactorLocked(), r.lastActivity);
        }
        r.callStart = false;
        synchronized (r.stats.getBatteryStats()) {
            r.stats.startRunningLocked();
        }
        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方法。

    private final String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
                boolean whileRestarting) throws TransactionTooLargeException {
        //如果app和thread存在,直接回调app进程onStartCommand方法,
        if (r.app != null && r.app.thread != null) {
            sendServiceArgsLocked(r, execInFg, false);
            return null;
        }
        //不存在,继续走流程
        realStartServiceLocked方法
    }
    

    ServiceRecord是Ams保存的服务记录,它和ActivityRecord类似。
    在realStartServiceLocked方法。

    private final void realStartServiceLocked(ServiceRecord r,
            ProcessRecord app, boolean execInFg) throws RemoteException {
        //app.thread不能是空。
        r.app = app;//设置ProcessRecord
        boolean created = false;
        try {
            ...
            app.thread.scheduleCreateService(r, r.serviceInfo,
                    mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
                    app.repProcState);
            created = true;
        } catch (DeadObjectException e) {
            throw e;
        } finally {
            ...
        }
        ...
        sendServiceArgsLocked(r, execInFg, true);
    }
    

    该方法通过ApplicationThread回调App的scheduleCreateService方法,向主线程发送一个CREATE_SERVICE消息,然后,执行handleCreateService方法。

    private void handleCreateService(CreateServiceData data) {
        LoadedApk packageInfo = getPackageInfoNoCheck(
                data.info.applicationInfo, data.compatInfo);
        Service service = null;
        try {
            //构建Service对象
            java.lang.ClassLoader cl = packageInfo.getClassLoader();
            service = (Service) cl.loadClass(data.info.name).newInstance();
        } catch (Exception e) {
        }
        try {
            //创建Service内部真实类
            ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
            context.setOuterContext(service);
            Application app = packageInfo.makeApplication(false, mInstrumentation);
            //attach方法
            service.attach(context, this, data.info.name, data.token, app,
                    ActivityManagerNative.getDefault());
            //生命周期方法。
            service.onCreate();
            mServices.put(data.token, service);
            try {
                ActivityManagerNative.getDefault().serviceDoneExecuting(
                        data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
            } catch (RemoteException e) {
            }
        } catch (Exception e) {
        }
    }
    

    首先,类加载器ClassLoader加载对应的Service类,调用类的newInstance方法,创建Service对象。
    然后,创建ContextImpl实现类,调用attach方法向Service内部赋值。执行Service的生命周期方法onCreate。
    最后,根据IBinder类型的token,将新建Service保存到Map中,这些过程和Activity的启动流程一样。
    我们再回到realStartServiceLocked方法,最后,调用sendServiceArgsLocked方法,该方法回调ApplicationThread的scheduleServiceArgs方法,发送的是SERVICE_ARGS消息。

    private void handleServiceArgs(ServiceArgsData data) {
        Service s = mServices.get(data.token);
        if (s != null) {
            try {
                ...
                int res;
                if (!data.taskRemoved) {
                    //调用onStartCommand方法
                    res = s.onStartCommand(data.args, data.flags, data.startId);
                } else {
                    s.onTaskRemoved(data.args);
                    res = Service.START_TASK_REMOVED_COMPLETE;
                }
            } catch (Exception e) {
            }
        }
    }
    

    在主线程处理消息时,调用Service的onStartCommand方法。到这里,从无到有启动一个Service就已经完成了,在开发中遇到的方法都已经执行到。如果该Service组件已经存在,我们再次执行startService方法,这时,ServiceRecord的ProcessRecord已被赋值过,同时,ProcessRecord内部ApplicationThread也存在,在bringUpServiceLocked方法,会调用sendServiceArgsLocked方法,回调App进程,触发onStartCommand方法。

    下面是一张Service启动时调用方法当流程图。 Service启动时调用方法当流程图.jpg

    总结流程

    在服务启动过程中,经历两个方法,onCreate和onStartCommand方法,他们都是通过Ams服务回调App进程,消息通知主线程调用。
    当多次启动服务时,实例化和创建方法只执行一次,开始方法会执行多次。


    任重而道远

    相关文章

      网友评论

          本文标题:Service启动流程

          本文链接:https://www.haomeiwen.com/subject/qolhkqtx.html