美文网首页
Service绑定流程

Service绑定流程

作者: gczxbb | 来源:发表于2018-12-18 14:01 被阅读7次

    Android系统的Service有两种启动方式,第一种是startService启动,第二种是bindService绑定。服务绑定状态时,多用于和其他组件通信。

    Intent intentNormal = new Intent(ServiceActivity.this, NormalService.class);
    startService(intentNormal);
    
    Intent intentNormalBind = new Intent(ServiceActivity.this, NormalService.class);
    bindService(intentNormalBind, conn, Service.BIND_AUTO_CREATE);
    

    本文分析在Activity组件中调用bindService方法,实现Service绑定的流程,解释一下Service的onBind方法,App自定义实现类ServiceConnection的#onServiceConnected方法调用时机。
    参考源码

    我们在Activity组件中调用bindService方法,看一下打印日志。

    AppServiceLifeCycle: LifeCycleService LifeCycleService 构造方法
    LifeCycleService onCreate 方法
    LifeCycleService onBind 方法
    

    触发三个方法,构造方法,创建方法和绑定方法。Activity组件继承Context的装饰类ContextWrapper,在它的bindService方法中,调用的是ContextImpl实现类的bindService方法。

    @Override
    public boolean bindService(Intent service, ServiceConnection conn,
                int flags) {
        warnIfCallingFromSystemProcess();
        return bindServiceCommon(service, conn, flags, Process.myUserHandle());
    }
    

    进入bindServiceCommon方法代码。

    private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
            UserHandle user) {
        IServiceConnection sd;
            //抛出conn空的异常
        if (mPackageInfo != null) {
            sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(),
                    mMainThread.getHandler(), flags);
        } else {
        }
        validateServiceIntent(service);
        try {
            IBinder token = getActivityToken();
            //Ams请求
            int res = ActivityManagerNative.getDefault().bindService(
                mMainThread.getApplicationThread(), getActivityToken(), service,
                service.resolveTypeIfNeeded(getContentResolver()),
                sd, flags, getOpPackageName(), user.getIdentifier());
            if (res < 0) {
                //异常
            }
            return res != 0;
        } catch (RemoteException e) {
        }
    }
    

    在该方法中,访问Ams服务,调用服务的bindService方法,传递参数包括ApplicationThread回调App进程,IBinder token代表该Activity在Ams中唯一标志,还有一个IServiceConnection对象。
    系统没有将我们自定义ServiceConnection传给Ams服务,根据它由LoadedApk获取IServiceConnection。从系统源码中可以看出,IServiceConnection是一个aidl文件,InnerConnection是Binder类型,继承IServiceConnection.stub类,进程通信的服务端,和ApplicationThread是原理一样,Ams服务回调App进程。看一下LoadedApk的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) {
                sd = map.get(c);
            }
            if (sd == null) {
                sd = new ServiceDispatcher(c, context, handler, flags);
                if (map == null) {
                    map = new ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>();
                    mServices.put(context, map);
                }
                map.put(c, sd);
            } else {
                sd.validate(context, handler);
            }
            return sd.getIServiceConnection();
        }
    }
    

    系统将ServiceConnection和ServiceDispatcher的关系保存在一个ArrayMap,根据Context和ServiceConnection定位ServiceDispatcher,未查到则创建一个新ServiceDispatcher。它的内部封装InnerConnection(Binder),ServiceConnection(服务回调),Context和ActivityThread。


    Service绑定Ams服务流程

    下面看一下ActivityManagerService的bindService方法处理过程。

    public int bindService(IApplicationThread caller, IBinder token, Intent service,
                           String resolvedType, IServiceConnection connection, int flags, String callingPackage,
                           int userId) throws TransactionTooLargeException {
        ...
        synchronized(this) {
            return mServices.bindServiceLocked(caller, token, service,
                    resolvedType, connection, flags, callingPackage, userId);
        }
    }
    

    委托Ams内部ActiveServices类。下面的都是该类的方法。

    int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
            String resolvedType, IServiceConnection connection, int flags,
            String callingPackage, int userId) throws TransactionTooLargeException {
    
        final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
        //ProcessRecord是空抛异常
    
        ActivityRecord activity = null;
        //根据token查找Ams中的ActivityRecord记录
        if (token != null) {
            activity = ActivityRecord.isInStackLocked(token);
            //记录是空返回0
        }
        ServiceRecord s = res.record;
    
        try {
            ...
            if ((flags&Context.BIND_AUTO_CREATE) != 0) {
                s.lastActivity = SystemClock.uptimeMillis();
                if (bringUpServiceLocked(s, service.getFlags(), callerFg, false) != null) {
                    return 0;
                }
            }
    
            if (s.app != null && b.intent.received) {
                try {
                    c.conn.connected(s.name, b.intent.binder);
                } catch (Exception e) {
                }
                if (b.intent.apps.size() == 1 && b.intent.doRebind) {
                    requestServiceBindingLocked(s, b.intent, callerFg, true);
                }
            } else if (!b.intent.requested) {
                requestServiceBindingLocked(s, b.intent, callerFg, false);
            }
        } finally {
            Binder.restoreCallingIdentity(origId);
        }
        return 1;
    }
    

    调用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方法。
    }
    

    然后,调用realStartServiceLocked方法,通过scheduleCreateService方法回调App进程,创建Service,生命周期方法onCreate。
    最后,bindServiceLocked方法会调用到requestServiceBindingLocked方法,回调App进程的scheduleBindService方法。回传参数IBinder(Ams的ServiceRecord记录),Intent。在App进程,发送BIND_SERVICE消息到ActivityThread的H中处理。

    private void handleBindService(BindServiceData data) {
        Service s = mServices.get(data.token);
        if (s != null) {
            try {
                data.intent.setExtrasClassLoader(s.getClassLoader());
                data.intent.prepareToEnterProcess();
                try {
                    if (!data.rebind) {
                        IBinder binder = s.onBind(data.intent);
                        //服务返回Binder
                        ActivityManagerNative.getDefault().publishService(
                                data.token, data.intent, binder);
                    } else {
                        s.onRebind(data.intent);
                        ActivityManagerNative.getDefault().serviceDoneExecuting(
                                data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
                    }
                    ensureJitEnabled();
                } catch (RemoteException ex) {
                }
            } catch (Exception e) {
            }
        }
    }
    

    根据token,查找绑定的Service类,调用Service的onBind方法。返回Binder对象,这时,服务已经被绑定。
    publishService方法,回访Ams服务,将Binder发布到Ams,由Ams负责通知客户端。三个参数,都是scheduleBindService方法传过来的。
    Ams的publishService方法,调用ActiveServices#publishServiceLocked方法。

    void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
        ...
        for (int i=0; i<clist.size(); i++) {
            ConnectionRecord c = clist.get(i);
            if (!filter.equals(c.binding.intent.intent)) {
                continue;
            }
            try {
                c.conn.connected(r.name, service);
            } catch (Exception e) {
        }
    }
    

    ConnectionRecord内部conn是InnerConnection,Ams服务利用它进程通信,通知App进程。调用InnerConnection的connected方法,并将Binder返回绑定触发者,即Activity组件中自定义的ServiceConnection类。ServiceDispatcher的connected方法。

    public void connected(ComponentName name, IBinder service) {
        if (mActivityThread != null) {
            mActivityThread.post(new RunConnection(name, service, 0));
        } else {
            doConnected(name, service);
        }
    }
    

    ServiceDispatcher构造方法传入Handler,它就是从ActivityThread获取的H类。看一下RunConnection任务。执行doConnected方法。

    public void doConnected(ComponentName name, IBinder service) {
        ServiceDispatcher.ConnectionInfo old;
        ServiceDispatcher.ConnectionInfo info;
        ...
        // If there is a new service, it is now connected.
        if (service != null) {
            mConnection.onServiceConnected(name, service);
        }
    }
    

    调用ServiceDispatcher内部ServiceConnection的方法。到这里,我们在开发中遇到的Service绑定最常见的两个方法都执行过了,注意,只有onBind方法返回Binder对象不空时,才会调用onServiceConnected方法。


    总结

    Service绑定流程与其他组件启动类似,向Ams注册要绑定的服务类,通过ApplicationThread类实现App回调通知。在Ams服务中,如果发现服务未创建时,首先通知App生成服务实例,生命周期方法onCreate。
    App进程Service绑定成功,将服务Binder通知到Ams服务,最后,Ams服务再利用IServiceConnection进程间业务接口将服务已经连接的事情通知在Activity中自定义的服务连接对象ServiceConnection,并告知它服务Binder。


    任重而道远

    相关文章

      网友评论

          本文标题:Service绑定流程

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