美文网首页android 技术梳理
从 Binder 通信机制角度谈 bindService 的启动

从 Binder 通信机制角度谈 bindService 的启动

作者: jkwen | 来源:发表于2021-02-07 15:37 被阅读0次

    前面按照书本内容走了一遍 bindService 启动梳理,Android 进阶解密阅读笔记5 那时的重点在于流程是怎么走的,这篇我准备从参与 Binder 机制的过程重新梳理下,侧重点在于客户端(也就是调用 bindService 方法的一方)是如何与服务端(提供服务功能的一方)建立通信连接的。

    //从 ContextImpl 的 bindService 方法开始
    IServiceConnection sd;
    if(mPackageInfo != null) {
        if(executor != null) {
            sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), executor, flags);
        } else {
            //这里会走这句代码创建 sd
            sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
        }
    }
    //LoadedApk
    private IServiceConnection getServiceDispatcherCommon(ServiceConnection c, Context context, Handler handler, Executor executor, int flags) {
        synchronized (mServices) {
            LoadedApk.ServiceDispatcher sd = null;
            ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);
            //通过带参构造方法创建 sd,其中下面 return 的 IServiceContention 就是内部类的对象实例
            //即 InnerConnection 的对象
            sd = new ServiceDispatcher(c, context, handler, flags);
            map.put(c, sd);
        }
       return sd.getIServiceConnection();
    }
    

    可见,当我们通过调用 bindService 方法进行 Service 绑定时,入参的 ServiceConnection 对象和 flags 标志被用来创建了 ServiceDispatcher 对象,Intent 对象被用在了创建 Service。

    再按之前梳理的走下去,会触发 Service 的 onBind 方法。该方法要求返回一个 IBinder 类型的值,这个返回值其实就是服务方的 Binder 实体。也就是服务端中那个继承自 Binder 且实现服务功能接口的类的实体。

    //AMS
    //token 实际是 ServiceRecord 类型
    //service 就是服务端提供的 Binder 实体
    public void publishService(IBinder token, Intent intent, IBinder service) {
        mServices.publishServiceLocked((ServiceRecord)token, intent, service);
    }
    void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
        if (b != null && !b.received) {
            b.binder = service;
            b.requested = true;
            b.received = true;
            ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections = r.getConnections();
            for (int conni = connections.size() - 1; conni >= 0; conni--) {
                ArrayList<ConnectionRecord> clist = connections.valueAt(conni);
                for (int i=0; i<clist.size(); i++) {
                    ConnectionRecord c = clist.get(i);
                    try {
                        //c.conn 就是前面我们提到的 InnerConnection 对象
                        //service 就是服务端的 Binder 实体
                        c.conn.connected(r.name, service, false);
                    }
                }
            }
        }
    }
    //InnerConnection
    public void connected(ComponentName name, IBinder service, boolean dead) {
        //这里取到的就是一开始用 ServiceConnection 和 flags 创建的 ServiceDispatcher 对象
        LoadedApk.ServiceDispatcher sd = mDispatcher.get();
        if (sd != null) {
            sd.connected(name, service, dead);
        }
    }
    //ServiceDispatcher
    public void connected(ComponentName name, IBinder service, boolean dead) {
        if (mActivityExecutor != null) {
            mActivityExecutor.execute(new RunConnection(name, service, 0, dead));
        } else if (mActivityThread != null) {
            //接下去会执行这句代码,
            mActivityThread.post(new RunConnection(name, service, 0, dead));
        } else {
            doConnected(name, service, dead);
        }
    }
    //RunConnection
    public void run() {
        if (mCommand == 0) {
            doConnected(mName, mService, mDead);
        } else if(mCommand == 1) {
            
        }     
    }
    //ServiceDispatcher
    public void doConnected(ComponentName name, IBinder service, boolean dead) {
        if (service != null) {
            //service 是服务端的 Binder 实体
            //mConnection 是一开始的入参 ServiceConnection 对象
            mConnection.onServiceConnected(name, service);
        } else {
            mConnection.onNullBinding(name);
        }  
    }
    

    所以,作为客户端是通过 ServiceConnection 的 onServiceConnected 方法与服务端建立了通信,通信的介质可以认为是 IBinder 对象。

    那么客户端拿到这个 IBinder 对象后又该怎么用呢?肯定不能直接用,也没法强制类型转换,具体要怎么去用呢,可以看下这篇 Binder 机制入门

    相关文章

      网友评论

        本文标题:从 Binder 通信机制角度谈 bindService 的启动

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