美文网首页
Service启动流程

Service启动流程

作者: LeoFranz | 来源:发表于2019-09-29 15:34 被阅读0次

    在context中一句startService()之后发生了什么

    Service 有绑定和启动两种调动形式

    启动Service

    image.png

    1、通过contextWrapper的mBase来实现startService方法,转到startServiceCommon,然后通过ActivityManagerServiceNative.getDefault()这个对象来启动服务,它实际就是AMS。
    2、上述对AMS.startService()方法是远程调动,在该方法中,AMS借助ActiveService这个辅助类来管理service的启动绑定停止等。其最后调用startServiceInnerLocked()
    3、上述方法转入bringUpServiceLocked(),最后跳转到realStartServiceLocked()进行具体的service启动实现
    4、在realStartServiceLocked中首先通过app.thread.scheduleCreateService()方法其实现类似于activity的启动,通过远程调用在APP的ApplicationThread中实现,并通过H传递消息到ActivityThread,具体处理方法为handleCreateService(),主要做了创建Service实例,创建Application对象并调用其onCreate(如果存在就不会调用),接着创建ContextImpl对象并通过Service.attach方法建立二者之间的联系,这个过程类似于activity的,最后调用Service的onCreate方法。然后service会被存储到activityThread的一个列表中,这个列表是一个ArrayMap叫做mServices。
    5、Service已经被创建了,后面通过类似的进程间通信流程调用service的onStartCommand方法。

    绑定Service

    image.png

    1、和启动service一样,从ContextWrapper开始bindService,最终调用contextImpl的bindServiceCommon()方法,

    private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
                handler, UserHandle user) {
            // Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser.
            IServiceConnection sd;
            if (conn == null) {
                throw new IllegalArgumentException("connection is null");
            }
            if (mPackageInfo != null) {
                sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
            } else {
                throw new RuntimeException("Not supported in system context");
            }
            validateServiceIntent(service);
            try {
                IBinder token = getActivityToken();
                if (token == null && (flags&BIND_AUTO_CREATE) == 0 && mPackageInfo != null
                        && mPackageInfo.getApplicationInfo().targetSdkVersion
                        < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
                    flags |= BIND_WAIVE_PRIORITY;
                }
                service.prepareToLeaveProcess(this);
                int res = ActivityManager.getService().bindService(
                    mMainThread.getApplicationThread(), getActivityToken(), service,
                    service.resolveTypeIfNeeded(getContentResolver()),
                    sd, flags, getOpPackageName(), user.getIdentifier());
                if (res < 0) {
                    throw new SecurityException(
                            "Not allowed to bind to service " + service);
                }
                return res != 0;
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
    

    mPackageInfo是一个LoadedApk实例对象,getServiceDispatcher()返回的是一个LoadedApk的静态内部类ServiceDispatcher中的InnerConnection对象,InnerConnection是ServiceDispatcher中的静态内部类,继承 了IServiceConnection.Stub。接下来看下getServiceDispatcher的实现

    public final IServiceConnection getServiceDispatcher(ServiceConnection c,
                Context context, Handler handler, int flags) {
            synchronized (mServices) {
                LoadedApk.ServiceDispatcher sd = null;
                ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);
                if (map != null) {
                    if (DEBUG) Slog.d(TAG, "Returning existing dispatcher " + sd + " for conn " + c);
                    sd = map.get(c);
                }
                if (sd == null) {
                    sd = new ServiceDispatcher(c, context, handler, flags);
                    if (DEBUG) Slog.d(TAG, "Creating new dispatcher " + sd + " for conn " + c);
                    if (map == null) {
                        map = new ArrayMap<>();
                        mServices.put(context, map);
                    }
                    map.put(c, sd);
                } else {
                    sd.validate(context, handler);
                }
                return sd.getIServiceConnection();
            }
        }
    

    可见serviceDIspatcher内部同时封装了serviceConnection和InnerConnection,起着连接两者的作用。如果存在相同的serviceConnection系统就会复用map中的sd。服务的调用可能是跨进程的,所以当Service和客户端完成连接后,ServiceConnection(定义在客户端)需要binder才能让远程服务端调用自己的方法,InnerConnection恰好充当了binder这个角色。
    继续上述bindServiceCommon方法,AMS通过bindService方法完成具体绑定过程。

    2、后续在AMS服务端调用ActiveService的bindServiceLocked方法,依次跳转到bringUpSericeLocked,realStartServiceLocked方法,后续流程和启动service类似。通过ApplicationThread完成Service的创建并执行其onCreate方法,不同的是Service绑定过程还会调用app.Thread.scheduleServiceLocked方法,这个实现方法在requestServiceBindingLocked中。

    3、然后通过ApplicationThread到ActvityThread的handleBindService处理。

    private void handleBindService(BindServiceData data) {
            //在前面成功执行onCreate后,会通过mServices.put()保存service
            //mServices是一个ArrayMap对象
            Service s = mServices.get(data.token);
         
            if (s != null) {
                try {
                    data.intent.setExtrasClassLoader(s.getClassLoader());
                    data.intent.prepareToEnterProcess();
                    try {
                        if (!data.rebind) {
                            //执行onBind()
                            IBinder binder = s.onBind(data.intent);
                            ActivityManager.getService().publishService(
                                    data.token, data.intent, binder);
                        } else {
                            s.onRebind(data.intent);
                            ActivityManager.getService().serviceDoneExecuting(
                                    data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
                        }
                        ensureJitEnabled();
                    } catch (RemoteException ex) {
                        throw ex.rethrowFromSystemServer();
                    }
                } catch (Exception e) {
                    if (!mInstrumentation.onException(s, e)) {
                        throw new RuntimeException(
                                "Unable to bind to service " + s
                                + " with " + data.intent + ": " + e.toString(), e);
                    }
                }
            }
        }
    

    原则上说,执行onBind之后service就已经和客户端连接上了,但是这是service自己的方法,客户端还不知道,所以需要回调客户端的ServiceConnection的onServiceConnected(),这个过程实现通过AMS的plushService()实现。

    此外多次绑定同一个Service,其onBind方法只会执行一次,除非service被终止了。

    4、对于上述plushService方法,交给ActiveServices的plushServiceLocked方法来处理,核心过程是c.conn.connected(r.name,service),c是CoonectionRcord,c.conn的类型是SericeDispatcher.InnerConnection,service就是Service的onBind方法返回额binder对象。

    5、在innerConnection中的connected方法具体实现是其引用的ServiceDispatcher.connected方法。该方法核心语句是mActivityThread.post(new RunConnection(name,service,0));mActivityThread就是ActivityThread.H,这样客户端ServiceConnection的方法就是在主线程被回调的。RunConnection中的run方法其实是简单调用了ServiceDispather的doConnected,前面已经描述,ServiceDispather内部保存了客户端的ServiceConnection对象,所以可以轻松地调用ServiceConnection中的公共方法。

    Service的停止和接触绑定过程,和上述类似。

    相关文章

      网友评论

          本文标题:Service启动流程

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