美文网首页
对Binder通信机制以及AIDL的理解

对Binder通信机制以及AIDL的理解

作者: 六怀雁 | 来源:发表于2022-01-05 16:35 被阅读0次

Binder通信机制理解
首先,我们通常说的binder驱动,并不是真有驱动,而是表示它运行在内核中,Binder IPC 是基于内存映射(mmap)来实现的,一次通信数据只拷贝一次,内核的数据缓存区跟服务端存在映射关系,所以服务端能直接读取内核数据。

image.png

一次binder通信数据传递过程
1. 客户端绑定并连接成功之后,会得到IBinder类型的对象,此对象就是BinderProxy,这个对象是在native层创建出来,此对象在创建的时候,native层还会把BpBInder对象指针传递进来.这俩是对应关系,BinderProxy中的native方法都会被调到BpBinder里面的方法中。
2. 客户端发起请求,最终会调到BinderProxy中的transact方法,再调进BinderProxy.transactNative --> BpBinder.transact --> IPCThreadState.transact
3. IPCThreadState也是在native层,主要是用来跟Binde驱动进行交互。IPCThreadState的代码一部分给客户端使用,一部分给服务端使用。这里客户端的IPCThreadState类似于socket编程中的客户端。IPCThreadState.transact最终会调到IPCThreadState.talkWithDriver,通过此方法会把数据写入Binder驱动中,如果是异步调用(比如aidl中使用oneway修饰符),直接就通信结束了,如果是同步的,还要再talkWithDriver,等服务端发送的调用结果,此时客户端处于阻塞状态。
4. 服务端也有一个IPCThreadState对象,类似于socket中的服务端,IPCThreadState在talkWithDriver()处于阻塞,等待Binder驱动的消息,当收到Binder驱动的消息后,数据会给传递到IPCThreadState.executeCommand()方法中,根据传递过来的数据,能找到BBinder(native层), BBinder跟java层的Binder对象也是对应关系。执行顺序为IPCThreadState.executeCommand() --> BBinder.transact() --> Binder$Stub.onTransact(),Binder$Stub就是服务端需要实现的Binder。
5. 客户端的IPCThreadState.talkWithDriver阻塞被唤醒,IPCThreadState从Binder驱动中读取数据。

image.png

AIDL生成java代码分析:

package com.autoai.test;

interface IMusicManager {

    boolean play();
    
}
/*
 * This file is auto-generated.  DO NOT MODIFY.
 */
package com.autoai.test;

public interface IMusicManager extends android.os.IInterface {
    /**
     * Local-side IPC implementation stub class.
     */
    public static abstract class Stub extends android.os.Binder implements com.autoai.test.IMusicManager {
        private static final java.lang.String DESCRIPTOR = "com.autoai.test.IMusicManager";

        /**
         * Construct the stub at attach it to the interface.
         */
        public Stub() {
            this.attachInterface(this, DESCRIPTOR);
        }

        /**
         * Cast an IBinder object into an com.autoai.test.IMusicManager interface,
         * generating a proxy if needed.
         */
        //客户端绑定服务端之后,拿到的IBinder对象,需要调用此方法,如果传入的obj是本地Binder对象,不需要转化
        //如果是远程Binder,那么obj就是BinderProxy对象,需要创建Binder代理对象
        public static com.autoai.test.IMusicManager asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            //如果是本地Binder
            if (((iin != null) && (iin instanceof com.autoai.test.IMusicManager))) {
                return ((com.autoai.test.IMusicManager) iin);
            }
            //如果是远程Binder,创建Binder代理
            return new com.autoai.test.IMusicManager.Stub.Proxy(obj);
        }

        @Override
        public android.os.IBinder asBinder() {
            return this;
        }

        //此方法服务端会调用,当收到客户端传递过来的数据,这里会给触发,服务端被触发的顺序为:
        //TCPThreadState.executeCommand-->BBinder.transact-->Binder$Stub.onTransact
        @Override
        public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
            java.lang.String descriptor = DESCRIPTOR;
            switch (code) {
                case INTERFACE_TRANSACTION: {
                    reply.writeString(descriptor);
                    return true;
                }
                case TRANSACTION_play: {
                    data.enforceInterface(descriptor);
                    boolean _result = this.play();
                    reply.writeNoException();
                    reply.writeInt(((_result) ? (1) : (0)));
                    return true;
                }
                default: {
                    return super.onTransact(code, data, reply, flags);
                }
            }
        }

        //这里就是客户端需要用到的代理,客户端调用Proxy中方法,向服务端发起请求
        private static class Proxy implements com.autoai.test.IMusicManager {

            //mRemote就是BinderProxy,与之对应的native层对象是BpBinder
            private android.os.IBinder mRemote;

            Proxy(android.os.IBinder remote) {
                mRemote = remote;
            }

            @Override
            public android.os.IBinder asBinder() {
                return mRemote;
            }

            public java.lang.String getInterfaceDescriptor() {
                return DESCRIPTOR;
            }

            @Override
            public boolean play() throws android.os.RemoteException {
                //_data是客户端传给服务端的数据
                android.os.Parcel _data = android.os.Parcel.obtain();
                //_replay是服务端传给客户端的数据
                android.os.Parcel _reply = android.os.Parcel.obtain();
                boolean _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    //BinderProxy调用transact,触发BpBinder.transact-->TCPThreadState.transact-->TCPThreadState.talkWithDriver
                    //TCPThreadState.talkWithDriver调用之后会处于等待状态,等待服务器返回数据
                    mRemote.transact(Stub.TRANSACTION_play, _data, _reply, 0);
                    _reply.readException();
                    //读取服务端返回的数据
                    _result = (0 != _reply.readInt());
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
        }

        static final int TRANSACTION_play = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    }

    public boolean play() throws android.os.RemoteException;
}

参考文章:
https://zhuanlan.zhihu.com/p/35519585
https://blog.csdn.net/learnframework/article/details/121645259
https://blog.csdn.net/freshui/article/details/55051268
https://blog.csdn.net/pi9nc/article/details/9749325/
https://blog.csdn.net/gykimo/article/details/8901192

相关文章

网友评论

      本文标题:对Binder通信机制以及AIDL的理解

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