Service是如何启动的?一文告诉你

作者: 程序老秃子 | 来源:发表于2022-08-06 21:27 被阅读0次

    前言

    这几天分析了一下的启动过程,于是乎,今天写一下Service是如何启动的; 给我的感觉是这些启动过程并不复杂,千万不要被一坨一坨的代码吓住了,虽然弯弯绕绕不少,重载函数一个接着一个,就向走迷宫一样,但只要抓住主线阅读,很快就能找到出口; 强调一下阅读系统源码,起码要对进程间通信要了解,对binder机制非常非常清楚,binder就是指南针,要不然你会晕头转向;强行阅读,就容易睡着。

    Service启动先来一张图感受一下

    这张图能够说明一个大致的流程,但是服务的启动肯定不是这么简单,但是我们先简单的总结一下,逐渐深入。服务的启动形式有两种,startService()和 binderService(),我们看startService()这一种。startService是ContextWrapper里面的方法。

    ContextWrapper.java

      @Override
       public ComponentName startService(Intent service) {
           return mBase.startService(service);//mBase这里指的是ContextImpl类
       }
    

    ContextImpl.java

       @Override
        public ComponentName startService(Intent service) {
            warnIfCallingFromSystemProcess();
            return startServiceCommon(service, mUser);
        }
    
      private ComponentName startServiceCommon(Intent service, UserHandle user) {
            try {
                //检验Intent
                validateServiceIntent(service);
                 ......
                ComponentName cn = ActivityManagerNative.getDefault().startService(
                    mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
                                getContentResolver()), getOpPackageName(), user.getIdentifier());
                 ......
                return cn;
            } catch (RemoteException e) {
                throw new RuntimeException("Failure from system", e);
            }
        }
    

    校验完Intent后,就调用ActivityManagerNative.getDefault(),获取一个IActivityManager对象,将启动Service这件事情交给了IActivityManager。我们看一下ActivityManagerNative的类定义

    public abstract class ActivityManagerNative extends Binder implements IActivityManager
    

    这种模式是不是非常熟悉啊? 继承了Binder,实现了一个IActivityManager接口,这个跟我们生成了远程服务通信生成的AIDL的java文件怎么那么像,现在告诉你,这就是为了远程服务通信做准备的,只是一般这种类我们都是自动生成的,ActivityManagerNative 是谷歌的人自己写

    一个完整的AID L有两部分,一个是个跟服务端通信的Stub,一个是跟客户端通信的Proxy; ActivityManagerNative就是Stub,阅读源码发现在ActivityManagerNative 文件中还有个ActivityManagerProxy,那么跟客户端通信的Proxy也有了。先看IActivityManager怎么获取的

    ActivityManagerNative.java

     static public IActivityManager getDefault() {
            return gDefault.get();
        }
    
      private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
            protected IActivityManager create() {
              //获取名为"activity"的服务,服务都注册到ServiceManager来统一管理
                IBinder b = ServiceManager.getService("activity");
                if (false) {
                    Log.v("ActivityManager", "default service binder = " + b);
                }
                IActivityManager am = asInterface(b);
                if (false) {
                    Log.v("ActivityManager", "default service = " + am);
                }
                return am;
            }
        };
    

    就是一个单例设计模式,获取到服务对象IBinder,把这个IBinder转换成IActivityManager返回了。现在由IActivityManager启动服务。

     public ComponentName startService(IApplicationThread caller, Intent service,
                String resolvedType, String callingPackage, int userId) throws RemoteException
        {
            Parcel data = Parcel.obtain();
            Parcel reply = Parcel.obtain();
            data.writeInterfaceToken(IActivityManager.descriptor);
            data.writeStrongBinder(caller != null ? caller.asBinder() : null);
            service.writeToParcel(data, 0);
            data.writeString(resolvedType);
            data.writeString(callingPackage);
            data.writeInt(userId);
    
            mRemote.transact(START_SERVICE_TRANSACTION, data, reply, 0);
    
            reply.readException();
            ComponentName res = ComponentName.readFromParcel(reply);
            data.recycle();
            reply.recycle();
            return res;
        }
    

    上面说了ActivityManagerProxy作为binder通信的客户端,ActivityManagerNative 作为binder通信的服务端; mRemote.transact()是binder通信的客户端发起方法,经过binder驱动,最后回到binder服务端ActivityManagerNative的onTransact()方法。

       @Override
        public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
                throws RemoteException {
                .......
            switch (code) {
                 case START_SERVICE_TRANSACTION: {
                            data.enforceInterface(IActivityManager.descriptor);
                            IBinder b = data.readStrongBinder();
                            IApplicationThread app = ApplicationThreadNative.asInterface(b);
                            Intent service = Intent.CREATOR.createFromParcel(data);
                            String resolvedType = data.readString();
                            String callingPackage = data.readString();
                            int userId = data.readInt();
                            ComponentName cn = startService(app, service, resolvedType, callingPackage, userId);
                            reply.writeNoException();
                            ComponentName.writeToParcel(cn, reply);
                            return true;
                        }
            }
            .......
        }
    

    ActivityManagerNative的真正实现是ActivityManagerService,所以binder通信的服务端的ActivityManagerService,ActivityManagerProxy.startService()最终调用ActivityManagerService.startService()。注意这就跨进程了,ActivityManagerService是一个服务端的进程。看ActivityManagerService中的startService方法。

    ActivityManagerService.java

     public ComponentName startService(IApplicationThread caller, Intent service,
                String resolvedType, String callingPackage, int userId)
                throws TransactionTooLargeException {
            ......
            synchronized(this) {
                .......
                ComponentName res = mServices.startServiceLocked(caller, service,
                        resolvedType, callingPid, callingUid, callingPackage, userId);
                Binder.restoreCallingIdentity(origId);
                return res;
            }
        }
    

    ActivityManagerService没有直接干这个活,而是把这个任务交给了mService, mService 是一个 ActiveServices 对象。在早期的安卓版本中并没有这个类,后来重构时抽出这个类专门用来管理Service.

    ActiveServices.java

        ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
                int callingPid, int callingUid, String callingPackage, int userId)
                throws TransactionTooLargeException {
                  ........
                  return startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
        }
    

    tartServiceInnerLocked调用了 bringUpServiceLocked(),bringUpServiceLocked()内部调用了realStartServiceLocked(),我们看realStartServiceLocked()方法。

    private final void realStartServiceLocked(ServiceRecord r,
                ProcessRecord app, boolean execInFg) throws RemoteException {
           .......
            try {
                .......
                app.thread.scheduleCreateService(r, r.serviceInfo,
                        mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
                        app.repProcState);
                r.postNotification();
                created = true;
            } catch (DeadObjectException e) {
                ....
            } finally {
               ....
            }
    
            requestServiceBindingsLocked(r, execInFg);
    
            updateServiceClientActivitiesLocked(app, null, true);
    
            // If the service is in the started state, and there are no
            // pending arguments, then fake up one so its onStartCommand() will
            // be called.
            if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
                r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
                        null, null));
            }
           // 进入onStartCommand()
            sendServiceArgsLocked(r, execInFg, true);
    
           ....
        }
    

    这里的关键是

     app.thread.scheduleCreateService(r, r.serviceInfo,
                        mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
    

    app 是要运行 Service 的进程对应的 ProcessRecord 对象,代表一个应用进程; 要区分一下,一般我们都是单方向通信,客户端将处理请求发送给服务端,服务端处理后返回,如果要服务端向客户端发送一个“请求”呢?这里的thread 是一个 ApplicationThreadProxy 对象,它是应用进程的 ApplicatonThread 对象在 AMS 端的代理,AMS 靠它来和应用进程进行通信。所以AMS和应用进程可以双向通信了。

    ApplicationThreadProxy.java

    public final void scheduleCreateService(IBinder token, ServiceInfo info,
            CompatibilityInfo compatInfo, int processState) throws RemoteException {
        Parcel data = Parcel.obtain();
        data.writeInterfaceToken(IApplicationThread.descriptor);
        data.writeStrongBinder(token);
        info.writeToParcel(data, 0);
        compatInfo.writeToParcel(data, 0);
        data.writeInt(processState);
        try {
            mRemote.transact(SCHEDULE_CREATE_SERVICE_TRANSACTION, data, null, IBinder.FLAG_ONEWAY);
        } catch (TransactionTooLargeException e) {
            throw e;
        }
        data.recycle();
    }
    

    执行mRemote.transact后,就会回调ApplicationThreadNative的onTransact,这是Binder的套路。

    ApplicationThreadNative.java

    public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
            throws RemoteException {
        switch (code) {
        case SCHEDULE_CREATE_SERVICE_TRANSACTION: {
            data.enforceInterface(IApplicationThread.descriptor);
            IBinder token = data.readStrongBinder();
            ServiceInfo info = ServiceInfo.CREATOR.createFromParcel(data);
            CompatibilityInfo compatInfo = CompatibilityInfo.CREATOR.createFromParcel(data);
            int processState = data.readInt();
            scheduleCreateService(token, info, compatInfo, processState);
            return true;
        }
        ...
    }
    

    内部调用scheduleCreateService,看上面的图,可以知道,scheduleCreateService是属于ApplicatonThread的。

    ApplicatonThread.java

     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);
            }
    

    发送一个消息,这个消息都是由H类处理的,H类就是系统Hander,专门处理系统请求的; 比如一些Activity的生命周期等全在这里面。这个 H对象是在应用进程的主线程中创建的,所以最终的结果是把创建 Service 的消息传到了主线程,因此Service是运行在主线程中的。

    H.java

    private class H extends Handler {
              .........
                public void handleMessage(Message msg) {
                
                if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
                switch (msg.what) {
                
                 case CREATE_SERVICE:
                        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceCreate");
                        handleCreateService((CreateServiceData)msg.obj);
                        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                }
            }
    

    ActivityThread.java

     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 {
                if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
                 //创建ContextImpl对象
                ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
                context.setOuterContext(service);
                 //创建Application对象
                Application app = packageInfo.makeApplication(false, mInstrumentation);
                service.attach(context, this, data.info.name, data.token, app,
                        ActivityManagerNative.getDefault());
                //回调onCreate方法
                service.onCreate();
                mServices.put(data.token, service);
                try {
                  //调用服务创建完成
                    ActivityManagerNative.getDefault().serviceDoneExecuting(
                            data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
                } catch (RemoteException e) {
                    // nothing to do.
                }
            } catch (Exception e) {
               .......
            }
        }
    

    到此Service的onCreate就回调了,那么onStartCommand()何时回调呢?在realStartServiceLocked中调用了sendServiceArgsLocked(r, execInFg, true),sendServiceArgsLocked与上面类似,最终也是发送了一个(SERVICE_ARGS)消息。

    ApplicationThread.java

    public final void scheduleServiceArgs(IBinder token, boolean taskRemoved, int startId,
                int flags ,Intent args) {
                ServiceArgsData s = new ServiceArgsData();
                s.token = token;
                s.taskRemoved = taskRemoved;
                s.startId = startId;
                s.flags = flags;
                s.args = args;
    
                sendMessage(H.SERVICE_ARGS, s);
            }
    

    ActivityThread.java

    private void handleServiceArgs(ServiceArgsData data) {
            Service s = mServices.get(data.token);
            if (s != null) {
                try {
                    if (data.args != null) {
                        data.args.setExtrasClassLoader(s.getClassLoader());
                        data.args.prepareToEnterProcess();
                    }
                    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;
                    }
    
                    QueuedWork.waitToFinish();
    
                    try {
                        ActivityManagerNative.getDefault().serviceDoneExecuting(
                                data.token, SERVICE_DONE_EXECUTING_START, data.startId, res);
                    } catch (RemoteException e) {
                        // nothing to do.
                    }
                    ensureJitEnabled();
                } catch (Exception e) {
                   ......
                }
            }
        }
    

    Service的onCreate的回调和onStartCommand的回调套路是完全一样的,朋友们可以自己体会,onCreate的回调先执行scheduleCreateService()方法,最终回调Service.onCreate(); onStartCommand的回调先执行scheduleServiceArgs()方法,最终回调Service.onStartCommand()

    总结一下:

    IActivityManager接口中定义了AMS向应用程序(本例中即Service)提供的多种API,Activity通过ActivityManagerProxy就可以使用这些API,向AMS发出请求

    所以是通过ActivityManagerProxy,调用ActivityManagerProxy的startService方法; 在内部调用transact,然后会调用ActivityManagerNative中的onTransact()方法,在该方法中,将会r完成AMS与Activity的连接并调用AMS的startService()方法,那么AMS是如何Service所在的应用程序呢?比如scheduleCreateService

    原来ApplicationThreadProxy 是应用进程的 ApplicatonThread 对象在 AMS 端的代理,AMS 靠它来和应用进程进行通信。这就是Activity与AMS之间的双向Binder连接;Activity用IActivityManager提供的APIActivityManagerService提出执行某个动作的请求(本例中是启动RemoteService),ActivityManagerService通过IApplicationThread提供的API来控制Activity所在的应用程序

    上面的分析省去了很多的内容,如果从进程角度看服务启动过程。

    • Process A进程:是指调用startService命令所在的进程,也就是启动服务的发起端进程

    • system_server进程:系统进程,是java framework框架的核心载体,里面运行了大量的系统服务,比如这里提供ApplicationThreadProxy,ActivityManagerService,这个两个服务都运行在system_server进程的不同线程中

    • Zygote进程:是由init进程孵化而来的,用于创建Java层进程的母体,所有的Java层进程都是由Zygote进程孵化而来

    • Remote Service进程:远程服务所在进程,是由Zygote进程孵化而来的用于运行Remote服务的进程。主线程主要负责Activity/Service等组件的生命周期以及UI相关操作都运行在这个线程; 另外,每个App进程中至少会有两个binder线程 ApplicationThread和ActivityManagerProxy

    启动流程:

    • Process A进程采用Binder IPC向system_server进程发起startService请求;

    • system_server进程接收到请求后,向zygote进程发送创建进程的请求;

    • zygote进程fork出新的子进程Remote Service进程;

    • Remote Service进程,通过Binder IPC向sytem_server进程发起attachApplication请求;

    • system_server进程在收到请求后,进行一系列准备工作后,再通过binder IPC向remote Service进程发送scheduleCreateService请求;

    • Remote Service进程的binder线程在收到请求后,通过handler向主线程发送CREATE_SERVICE消息;

    • 主线程在收到Message后,通过发射机制创建目标Service,并回调Service.onCreate()方法。 到此,服务便正式启动完成。当创建的是本地服务或者服务所属进程已创建时,则无需经过上述步骤2、3,直接创建服务即可

    有需要文章中完整代码的同学 现在点击此处传送门 即可免费获取

    现在点击链接还可以获取《更多 Android 源码解析+核心笔记+面试真题》

    最后我想说:

    学习没有捷径可言,我们要注意记学习,不仅要记,还要写心得体会,文字笔记、画图、总结等,方式很多,但是一定要自己认真去做,不要太相信自己的记忆,只有反复记忆,加深理解才行

    同时,对于程序员而言,不单单是死记硬背,我们有更好的方式去学习,比如写demo去验证。复习知识点时,要及时跟你做过的项目结合起来,这样在面试时就知道怎么聊了,由项目讲到知识点,由一个知识点串联到另一个知识点。复习到一定阶段,可以尝试着去把这些东西串联起来,由点及面,形成知识体系

    对于程序员来说,要学习的知识内容、技术有太多太多,要想不被环境淘汰就只有不断提升自己,从来都是我们去适应环境,而不是环境来适应我们

    技术是无止境的,你需要对自己提交的每一行代码、使用的每一个工具负责,不断挖掘其底层原理,才能使自己的技术升华到更高的层面

    Android 架构师之路还很漫长,与君共勉

    相关文章

      网友评论

        本文标题:Service是如何启动的?一文告诉你

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