Android Service启动(一) startService()启动过程以及原理解析

       Service分为两种工作状态,启动状态和绑定状态,通过调用startService()可进入启动状态,通过bindService()可进入绑定状态,本篇文章主要讲解startService()启动Service的过程。(额,android的版本还是26)

      我们平时通过startService()启动一个Service的时候,最终都是调用的ContextWrapper的startService(),我们来看下这个方法

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

上述方法中调用了mBase对象的startService()方法,mBase的类型是Context,Context的实现类是ContextImpl,我们来看下ContextImpl的startService()方法

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

 

private ComponentName startServiceCommon(Intent service, boolean requireForeground,
        UserHandle user) {
    try {

        ......

        //调用了ActivityManagerService的startService()方法
        ComponentName cn = ActivityManager.getService().startService(
            mMainThread.getApplicationThread(), service, 
            service.resolveTypeIfNeeded(
            getContentResolver()), requireForeground,
            getOpPackageName(), user.getIdentifier());

            ......

            return cn;
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

我们可以看到在ContextImpl的startService()方法中,调用了startServiceCommon()方法,在startServiceCommon()中,通过ActivityManager.getService()获取到ActivityManagerService的对象,然后调用了ActivityManagerService的startService()方法

@Override
public ComponentName startService(IApplicationThread caller, Intent service,
 String resolvedType, boolean requireForeground, String callingPackage, int userId)
            throws TransactionTooLargeException {
        
    ......

    synchronized(this) {
           
        ......

        ComponentName res;
        try {
            res = mServices.startServiceLocked(caller, service,
                    resolvedType, callingPid, callingUid,
                    requireForeground, callingPackage, userId);
        } finally {
            Binder.restoreCallingIdentity(origId);
        }
        return res;
    }
}

在上述方法中,通过mServices对象调用了startServiceLocked()方法,mServices是ActiveServices类的对象,可以看做是辅助ActivityManagerServices来管理Service的类,我们来看下它的startServiceLocked()方法

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

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

在该方法的最后,调用了startServiceInnerLocked()方法

ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r, boolean callerFg, boolean addToStarting)
        throws TransactionTooLargeException {
        
    ......

    String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
       
    ......

    return r.name;
}

调用了bringUpServiceLocked()方法,该方法也是启动Service过程中比较重要的一个方法

private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,boolean whileRestarting, boolean permissionsReviewRequired)
        throws TransactionTooLargeException {
        
    /*
     * 个人理解:
     * 由本方法的参数可知,r是ServiceRecord的对象,ServiceRecord代表着一个Service记录
     * 联系整个Service的启动过程可知:
     * 首次调用startService()启动一个Service时候,r.app应该为null,下面的if判断不成立
     * 如果不是首次调用startService()方法,则下面的if判断成立,调用 
       sendServiceArgsLocked()方法,然后return,在sendServiceArgsLocked()方法中最终会调 
       用Service的onStartCommand()方法,这也是为什么非首次调用startService()方法时,不会 
       调用Service的onCreate(),而是每次都会调用onStartCommand()方法
     * 此处不对sendServiceArgsLocked()方法做过多解释,稍后下文中会讲到,希望读者能理解该方法 
       的作用,并且理解对应同一个Service,为什么只有首次调用startService()时,才会调用 
       Service的onCreate()方法,但是每次都会调用onStartCommand()方法
     */       
    if (r.app != null && r.app.thread != null) {
        sendServiceArgsLocked(r, execInFg, false);
        return null;
    }

    ......

    ProcessRecord app;

    if (!isolated) {
        app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
        ......    
        if (app != null && app.thread != null) {
            try {
                app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, 
mAm.mProcessStats);
                //执行realStarServiceLocked(),开始正式执行Servcie的启动过过程
                realStartServiceLocked(r, app, execInFg);
                return null;
            } catch (TransactionTooLargeException e) {
                ......
            }
        }
    } else {
        ......
    }

   ......

   return null;
}

在上述方法的注释中,我已经讲的比较详细了,我再总结一下,在上述的bringUpServiceLocked()方法中,若不是首次执行startService()方法,会直接调用sendServiceArgsLocked()方法,在sendServiceArgsLocked()方法中,会最终执行Service的onStartCommand()方法,如果是首次调用startService()方法,会按照正常的启动Service的代码逻辑来执行,会调用realStartServiceLocked()方法来正式执行Service的启动过程过程,在realStartServiceLocked()中,其实也会调用sendServiceArgsLocked()方法,这也是我理解的为什么多次调用startService()方法,只有首次调用的时候会执行Service的onCreate()方法,但是每次都会执行onStartCommand()方法。下面我们来分析下realStartServiceLocked()方法的代码逻辑和执行过程,在分析的过程中同样会涉及到sendServiceArgsLocked()方法。

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

        /* r是ServiceRecord的对象,对应了一个Service 
         * r.app是ProcessRecord的对象,对应了app所在的进程
         * 首次调用startService()时,会执行本方法
         * 而r.app = app的作用相当于把Service与进程关联起来
         * 因此不是首次调用startService()方法的过程中,当执行到bringUpServiceLocked()方法 
          时,r.app != null && r.app.thread != null的判断会成立,会执行 
          sendServiceArgsLocked()方法,便不会执行到本方法中来
         */
        r.app = app;
        
        ......

        try {
            
            ......

            //app.thread其实就是ActivityThread中ApplicationThread类的对象,
            //调用ApplicationThread的scheduleCreateService()方法
            //顾名思义,该方法就最终调用的应该就是Service的onCreate()方法 
            app.thread.scheduleCreateService(r, r.serviceInfo,
                    mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
                    app.repProcState);
            ......
        } catch (DeadObjectException e) {
            ......
        } finally {
            ......    
        }

        /*
         * 该方法是通过bindService()绑定Service的时候才去真正的调用,从而调用onBind()方法
         * 当通过startService()方法来开启一个Service的时候,该方法内部的逻辑不成立
         * 因startService()的过程基本不涉及到该方法,在下一篇讲解bindService()的绑定过程的 
           博客会详细讲解这块内容,本文中先忽略
         */
        requestServiceBindingsLocked(r, execInFg);

        ......

        /* 该方法通过startService()开启一个Service的时候会去真正的调用,从而调用 
           onStartCommon()方法
         * 当通过bindService()来绑定一个Service的时候,该方法的内部逻辑不成立
         * 稍后会讲到这个方法相关的内容
         */
            
        sendServiceArgsLocked(r, execInFg, true);
        
        ......

}

需要提一句的是,不论是startService()方法或是bindService()方法最终都会调用这个方法,最大的不同之处我已经在注释里已经讲的很清楚了,这里我就不再多说了,下面我们先看下上述方法中提到的app.thread.scheduleCreateService()方法,其实就是ActivityThread中ApplicationThread的scheduleCreateService()方法,看下Service的onCreate()是怎么执行的,然后再看下sendServiceArgsLocked()方法是怎么执行的onStartCommand()方法

public final void scheduleCreateService(IBinder token,
                ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
            updateProcessState(processState, false);
            CreateServiceData s = new CreateServiceData();
            s.token = token;
            s.info = info;
            s.compatInfo = compatInfo;

            sendMessage(H.CREATE_SERVICE, s);
}

如果看过我前几篇Activity启动相关博客的朋友,对上述方法这种类型的代码结构应该不陌生,基本上和Activity启动过程中调用的ApplicationThread方法都是一致的,调用sendMessage()方法,通过Handler发送一个消息,然后在Handler的handleMessage()方法中去处理这个消息,这一小块的相关代码我就不详细说了,也比较简单,不过还是把代码粘贴出来。

private void sendMessage(int what, Object obj) {
    sendMessage(what, obj, 0, 0, false);
}
private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
        if (DEBUG_MESSAGES) Slog.v(
            TAG, "SCHEDULE " + what + " " + mH.codeToString(what)
            + ": " + arg1 + " / " + obj);
        Message msg = Message.obtain();
        msg.what = what;
        msg.obj = obj;
        msg.arg1 = arg1;
        msg.arg2 = arg2;
        if (async) {
            msg.setAsynchronous(true);
        }
        mH.sendMessage(msg);
}

下面我们来看下在mH这个Handler的handleMessage()方法中是怎么处理这个事件的

public void handleMessage(Message msg) {
        ......
        switch (msg.what) {

            ......

            case CREATE_SERVICE:
                Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, ("serviceCreate: " + String.valueOf(msg.obj)));
                handleCreateService((CreateServiceData)msg.obj);
                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                break;
               
           ......     
           
        }
       
    ......

}

由上述方法可知,在Handler的handleMessage()方法中,处于这个事件时,回去调用handleCreateService()方法,我们来看下这个方法

private void handleCreateService(CreateServiceData data) {

        ......

        //通过getPackageInfoNoCheck()方法获取一个LoadedApk的对象
        LoadedApk packageInfo = getPackageInfoNoCheck(
                data.info.applicationInfo, data.compatInfo);
        Service service = null;
        try {
            //通过反射的方式,调用ClassLoader的loadClass()方法,创建一个Service对象
            java.lang.ClassLoader cl = packageInfo.getClassLoader();
            service = (Service) cl.loadClass(data.info.name).newInstance();
        } catch (Exception e) {
            ......
        }

        try {

            ......

            //创建一个ContextImpl对象
            ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
            context.setOuterContext(service);

            //获取Application对象
            Application app = packageInfo.makeApplication(false, mInstrumentation);
            //调用Service的attach()方法
            service.attach(context, this, data.info.name, data.token, app,
                    ActivityManager.getService());
            //调用Service的onCreate()方法
            service.onCreate();
            mServices.put(data.token, service);
            ......
        } catch (Exception e) {
            ......
        }
}

     上述方法的注释中已经解释的很清楚了,我就不多做解释了,不过需要提一点的是,在上述方法中有两个方法getPackageInfoNoCheck()以及packageInfo.makeApplication()这个两个方法,getPackageInfoNoCheck()方法获取的是一个LoadedApk对象,LoadedApk对象是apk文件在内存中的表示,apk文件的相关信息,比如apk文件中的资源,甚至是代码里面的Activity、Service等组件的信息都可以通过此对象获取,而且packageInfo.makeApplication()方法获取的是一个Application对象,若Application已经创建过,则直接return之前创建的Application对象,对这两个方法,这里我就简单的描述一下,就不贴出代码解释了,有想了解的朋友,可以看一下我之前的一篇博客  Android Activity启动(一) Application创建的过程以及原理分析,也涉及到相关的内容,讲解的也比较详细。到此为止,Service的onCreate()方法的执行流程已经介绍完毕了。

    我们再次回到realStartServiceLocked()中来,总结一下该方法中app.thread.scheduleCreateService()方法,调用了ApplicationThread的scheduleCreateService()方法,通过Handler处理事件,调用了ActivityThread的handleCreateService()方法,通过反射的方式获取Service的对象,然后依次调用Service的attach()方法和onCreate()方法。

   下面我们来继续看下realStartServiceLocked()方法中,先简单的看下requestServiceBindingLocked()方法执行后无作用。

private final void requestServiceBindingsLocked(ServiceRecord r, boolean execInFg)
        throws TransactionTooLargeException {
    //在startService()的过程中bindings.size() = 0,不会执行for循环
    for (int i=r.bindings.size()-1; i>=0; i--) {
        IntentBindRecord ibr = r.bindings.valueAt(i);
        if (!requestServiceBindingLocked(r, ibr, execInFg, false)) {
            break;
        }
    }
}

简单的说,就是因为在startService()的过程中没有对bindings添加值,而bindings.size() = 0,导致没有进入到for循环,bindlings是在bindService()过程中添加值的,有兴趣的朋友可以去了解一下,这里我就不多说了

然后我们看下之后执行的sendServiceArgsLocked()方法

private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
            boolean oomAdjusted) throws TransactionTooLargeException {
        /*
         * 当通过bindService()的方式调用到本方法时,N的值是0,后面的逻辑也都不会执行
         * 这也是为什么同样startService()和bindService()方法都会执行该方法,但是结果却不同
         * 具体pendingStarts是在哪里赋值的,我就不再多提了,有兴趣的朋友可以了解一下,应该比较 
           容易就能找到答案了
         */
        final int N = r.pendingStarts.size();
        if (N == 0) {
            return;
        }        

        ......

        try {
            //调用ActivityThread类中ApplicationThread的scheduleServiceArgs()方法
            r.app.thread.scheduleServiceArgs(r, slice);
        } catch (TransactionTooLargeException e) {
            ......
        } catch (RemoteException e) {
            ......
        } catch (Exception e) {
            ......
        }

        ......
}

我们可以看到,在上述方法中,会调用ActivityThread类中ApplicationThread的scheduleServiceArgs()方法,我们来看下这个方法。   

public final void scheduleServiceArgs(IBinder token, ParceledListSlice args) {
     List list = args.getList();

     for (int i = 0; i < list.size(); i++) {
         ServiceStartArgs ssa = list.get(i);
         ServiceArgsData s = new ServiceArgsData();
         s.token = token;
         s.taskRemoved = ssa.taskRemoved;
         s.startId = ssa.startId;
         s.flags = ssa.flags;
         s.args = ssa.args;

         sendMessage(H.SERVICE_ARGS, s);
     }
}

  

private void sendMessage(int what, Object obj) {
    sendMessage(what, obj, 0, 0, false);
}
private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
    if (DEBUG_MESSAGES) Slog.v(
        TAG, "SCHEDULE " + what + " " + mH.codeToString(what)
        + ": " + arg1 + " / " + obj);
    Message msg = Message.obtain();
    msg.what = what;
    msg.obj = obj;
    msg.arg1 = arg1;
    msg.arg2 = arg2;
    if (async) {
        msg.setAsynchronous(true);
    }
    mH.sendMessage(msg);
}

又是相似的代码,在scheduleServiceArgs()方法中调用sendMessage()方法,最终通过mH这个Handler对象发送了一个事件,我们来看下载mH这个Handler对象的handleMessage()方法中是怎么处理的

public void handleMessage(Message msg) {
    if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
    switch (msg.what) {
                
        ......
                               
        case SERVICE_ARGS:
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, ("serviceStart: " + String.valueOf(msg.obj)));
            handleServiceArgs((ServiceArgsData)msg.obj);
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
            break;
                
        ......
    }
    ......    
}

我们可以看到,在handleMessage()方法中,针对该消息,最终会调用handleServiceArgs()来处理

private void handleServiceArgs(ServiceArgsData data) {
    Service s = mServices.get(data.token);
    if (s != null) {
        try {
            ......
            if (!data.taskRemoved) {
                //调用Service的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的通过调用startService()的启动过程就介绍完毕了。

总结一下,在调用startService()来启动一个Service的时候,回去调用ContextImpl的startService()方法,从而调用ActivityManagerService的startService(),在启动的过程中,如果startService()方法不是首次调用的话,那么不会执行Service的onCreate()方法,只会执行Service的onStartCommand()方法,如果是首次调用startService(),则会有至少两次涉及到跨进程通信,首先是去调用ActivityThread中ApplicationThread里的方法来执行Service的onCreate()方法,执行完毕之后,同样会再执行ApplicationThread中的方法来执行Service的onStartCommand()方法。

本篇博客到此结束,欢迎批评指正,下一篇博客将介绍通过bindService()来绑定一个Service的过程。

你可能感兴趣的:(Android)