Android中Service启动原理分析

在Android开发中,对于应用开发者来说,通过Context的startService来启动一个服务的方法再熟悉不过了,那么startService到底是怎么启动一个Service的呢?这里为了直观的分析流程,就从startService方法开始。

一、Service启动流程总结

本来启动流程的总结应该放在最后,这里为了便于以后阅读时更清析,把两张总结图放在前面。下面这张图相对比较抽象。

再来看一张具体的流程图

二、启动流程及原理详细分析

通常我们在Activity、Application等地方调用的startService()方法,根据Context的类继承关系,实际上是在ContextImpl中实现的startService方法,如下

@Override
    public ComponentName startService(Intent service) {
        warnIfCallingFromSystemProcess();
        //核心方法
        return startServiceCommon(service, mUser);
    }

private ComponentName startServiceCommon(Intent service, UserHandle user) {
        ...
        //拿到AMS的binder对象,调用AMS中的startService方法
        ComponentName cn = ActivityManagerNative.getDefault().startService(
                mMainThread.getApplicationThread(), service,
                service.resolveTypeIfNeeded(getContentResolver()), user.getIdentifier());
        return cn;
    }

public ComponentName startService(IApplicationThread caller, Intent service,
                                      String resolvedType, int userId) {
        ...
        synchronized (this) {
            ...
            //核心步骤
            ComponentName res = mServices.startServiceLocked(caller, service,
                    resolvedType, callingPid, callingUid, userId);
            return res;
        }
    }

//继续跟进
ComponentName startServiceLocked(IApplicationThread caller,
            Intent service, String resolvedType,
            int callingPid, int callingUid, int userId) {
        ...
        //根据intent查询到service的ServiceRecord对象
        ServiceLookupResult res =
            retrieveServiceLocked(service, resolvedType,
                    callingPid, callingUid, userId, true, callerFg);
        ...
        ServiceRecord r = res.record;
        ...
        //用作之后准备调用startCommand用
        r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
                service, neededGrants));

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

到这里了,我们重点看一下startServiceInnerLocked(),最终会调用到ActivityService中的bringUpServiceLocked()方法。

private final String bringUpServiceLocked(ServiceRecord r,
            int intentFlags, boolean execInFg, boolean whileRestarting) {

        //service所在进程已经启动,且进程已经和AMS互相绑定
        if (r.app != null && r.app.thread != null) {
            //Service中onStartCommand的调用地方
            sendServiceArgsLocked(r, execInFg, false);
            return null;
        }

        //Service所在进程已经启动,但Service还没有启动
        ProcessRecord app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
        if (app != null && app.thread != null) {
            //真正启动Service
            //调用Service的onCreate方法与onStartCommand()方法
            realStartServiceLocked(r, app, execInFg);
        }

        //Service所在进程没有启动的情况
        if (app == null) {
            //启动进程
            app = mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
                    "service", r.name, false, isolated, false)
        }
        ...
        //添加到列表中,等进程启动完之后再来处理service的启动。
        if (!mPendingServices.contains(r)) {
            mPendingServices.add(r);
        }
        ...
        return null;
    }

上面代码块中启动Service所在进程的方法可以参考前面应用程序进程启动流程分析,逻辑是一样的。

下面继续跟进一步realStartService()方法,看看具体是怎么实现的,还是在ActivityService中

private final void realStartServiceLocked(ServiceRecord r,
                                              ProcessRecord app, boolean execInFg) throws RemoteException {
        ...
        //这里的ServiceRecord实际上是binder对象
        r.app = app;
        ...
        //AMS向应用端发起IPC调用,当应用端收到消息之后就会创建Service,执行Service里面的onCreate().
        app.thread.scheduleCreateService(r, r.serviceInfo,
                mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
                app.repProcState);
        ...
        //触发onStartCommand()方法
        sendServiceArgsLocked(r, execInFg, true);
    }

从上面这段围代码我们知道,当AMS向应用端发起IPC调用创建Service并调用onCreate(),那么当应用端收到这个IPC消息之后,到底是如何创建Service并调用onCreate()方法的呢?在我们熟悉的ActivityThread类中

private void handleCreateService(CreateServiceData data) {
        ...
        //获取到Service的相关信息,比如packageName, className等
        LoadedApk packageInfo = getPackageInfoNoCheck(
                data.info.applicationInfo, data.compatInfo);
        Service service = null;
        try {
            //通过LoadedApk的ClassLoader加载出来Service的实例对象
            java.lang.ClassLoader cl = packageInfo.getClassLoader();
            service = (Service) cl.loadClass(data.info.name).newInstance();
        } catch (Exception e) {
        }

        ...
        //创建该Service所需要的上下文
        ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
        context.setOuterContext(service);

        //创建Application,实际上是应用程序启动的时候Application就已经创建好了,这里直接返回创建好的
        Application app = packageInfo.makeApplication(false, mInstrumentation);

        //调用Service中的attach()方法
        service.attach(context, this, data.info.name, data.token, app,
                ActivityManagerNative.getDefault());

        //Service的onCreate()方法调用
        service.onCreate();

        mServices.put(data.token, service);
    }

从上面的注释已经很清楚的知道Service是如何创建,以及生命周期方法attach()、onCreate()的调用。我们知道Service中还有一个重要的方法onStartCommand(),这个方法是在我们每次startService的时候都会回调一次,那这个方法到底是怎么调用起来的呢?其实从上面代码中已经出现过,就是在ActivityService中执行了realStartServiceLocked()函数中调用的sendServiceArgsLocked()函数,看看这个函数是如何实现的

private final void sendServiceArgsLocked(ServiceRecord r,...) {
    while(r.pendingStarts.size() > 0) {
        StartItem si = r.pendingStarts.remove(0);
        ...
        //通过binder对象调用到应用端ActivityThread中的scheduleServiceArgs()
        r.app.thread.scheduleServiceArgs(r, ...);
    }
}

//在ActivityThread中
public final void scheduleServiceArgs(IBinder token, boolean taskRemoved, int startId,
                                              int flags, Intent args) {
            ServiceArgsData s = new ServiceArgsData();
            ...
            //发送到主线程消息队列
            sendMessage(H.SERVICE_ARGS, s);
        }

//处理消息的函数
private void handleServiceArgs(ServiceArgsData data) {
        Service s = mServices.get(data.token);
        if (s != null) {
            ...
            //onStartCommand()终于被调用了,从前面通过发送Message到主线程消息队列
            //我们知道onStartCommand()是在主线程中调用的,因此是不处理耗时操作
            res = s.onStartCommand(data.args, data.flags, data.startId);
            ...
        }
    }

到这里,Service的启动流程就讲完了。

发布了9 篇原创文章 · 获赞 3 · 访问量 688

猜你喜欢

转载自blog.csdn.net/xj_hnust/article/details/98374919