Service启动流程

2019-01-28  本文已影响3人  gczxbb

前面的文章分析过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进程,消息通知主线程调用。
当多次启动服务时,实例化和创建方法只执行一次,开始方法会执行多次。


任重而道远

上一篇下一篇

猜你喜欢

热点阅读