关于binder

关于binder

  binder是安卓中跨进程通信的一种方式,是安卓系统通信机制中及其重要的一环,很多系统调用比如AMS,SM,都是通过binder实现的。

为什么是binder

  在Linux中有Socket,管道等跨进程通信方式,为什么还要binder来完成IPC呢?
  出于效率和安全。首先,binder效率较Socket来说相对要高。其次,socket只能在上层协议进行验证操作(应用id在数据报中传输,容易被修改),ip和端口都可以手动输入来连接服务端。binder在内核为传输安全提供了支持,可以自动为发送方添加应用id/进程id。

binder和AIDL

  在安卓中进行进程间通讯我们一般选择AIDL。首先创建对应的aidl接口,声明远程方法。如果涉及对象作为参数,则该对象要实现Pracelable接口。并且对该类要单独声明对应的aidl文件。完成一系列声明后,编译项目则可用自动生成的对应类进行进程间通讯了。
  仔细观察/build/generated/aidl/ 目录下生成的对应类,会发现其也是利用binder相关类来实现的。这里引出了一个问题:AIDL在安卓进程间通讯扮演什么角色。
  其实我们把自动生成的类copy一份,然后删除aidl文件,会发现通讯能正常进行。因此可以得出结论:

aidl并不是进程间通讯所必须,而是作为一个辅助工具,帮我们快速构建进程通讯相关代码。

对binder的总结

  要了解binder及其原理,我倾向从三个方面入手(参考这篇博客):

1.binder怎么知道要调哪个进程的哪个方法。
2.怎么传递参数。
3.怎么优雅的实现以上两点。

  事实上,在binder跨进程通信中存在四个角色。分别是 客户端(client),服务端(server),服务管理器(Server Manager),binder驱动。
  服务端会先向服务管理器注册自己,也就是ServerManager上会先存储Server相关的信息,当客户端调用对应方法时,请求的实际上是binder驱动,由binder驱动去查阅哪个进程注册了对应的信息,然后告诉Server去调用对应的方法,结果同样由binder驱动返回。这之间的参数传递由序列化(Parcelable)实现。

源码分析

  所谓进程间通讯,无非就是值的传递。在binder中通过方法调用的参数传递和返回值来完成。
  既然是方法调用,首先需要定义行为。有哪些可以调用的方法,例如:

public interface mInterfaceImp extends IInterface {
    public static final int FUN_ADD_BOOK = 101;
    public static final int FUN_GET_BOOK_LIST = 102;
    public static final int REGISTER_LISTENER = 103;
    public static final int UNREGISTER_LISTENER = 104;

    ...

    void addBook(Book book);

    List<Book> getBookList();

    void registerListener(RegisterListener listener);

    void unRegisterListener(RegisterListener listener);
}

  定义四个整形常量是为了表示四个方法,通过服务端和客户端协商,某个具体的数字(例如101)可以代表一个具体的方法(addBook)。继承IInterface接口是为了使该接口具备化身binder的能力(并不真是binder,由子类实现)。这个后面会讲。
  定义完行为后就需要服务端和客户端都具有这些共同的行为,并且这些行为是可以跨进程交流的。怎么做呢,用binder。
  Binder实现了IBinder接口,在内核有binder驱动支持,可以进行进程间通讯。在这里可以理解成IBinder代表进程间通讯的能力。
  试着用一个binder的子类来实现我们上面定义的接口,使其具有我们想要的行为。也就是说,这些行为有了进程间通信的能力。

public static abstract class Stub extends Binder implements mInterfaceImp {
        private static final java.lang.String DESCRIPTOR = "aidl.lInterface";
        public Stub(){
            this.attachInterface(this,DESCRIPTOR);//注册binder,注册后,queryLocalInterface方法将会返回当前binder
        }

        @Override
        public IBinder asBinder(){//化身为binder的能力(自己就是)
            return this;
        }

        //该方法由binder驱动调用,在这里通过与客户端协商好的id来分辨客户端要调哪个方法。参数通过Parcelable传递
        @Override
        protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
            switch (code) {
                case INTERFACE_TRANSACTION:
                    reply.writeString(DESCRIPTOR);
                    return true;
                case FUN_ADD_BOOK:
                    data.enforceInterface(DESCRIPTOR);
                    Book book;
                    if(0!=data.readInt()){
                        book = Book.CREATOR.createFromParcel(data);
                    }else {
                        book = null;
                    }
                    reply.writeNoException();
                    addBook(book);
                    return true;
                case FUN_GET_BOOK_LIST:
                    data.enforceInterface(DESCRIPTOR);
                    reply.writeNoException();
                    reply.writeTypedList(getBookList());
                    return true;
                case REGISTER_LISTENER:
                    data.enforceInterface(DESCRIPTOR);
                    IBinder iBinder = data.readStrongBinder();
                    RegisterListener registerListener = RegisterListener.Stub.asInterface(iBinder);
                    this.registerListener(registerListener);
                    reply.writeNoException();
                    break;
                case UNREGISTER_LISTENER:


                    break;
            }
            return super.onTransact(code, data, reply, flags);
        }

        //静态方法,用于判断当前所在进程是否和当前binder在同一进程,见上面的构造方法,如果在同一进程,那么queryLocalInterface应该有值,反之代表不在同一进程,返回一个代理类。
        public static mInterfaceImp asInterface(IBinder iBinder){
            if(iBinder==null){
                return null;
            }
            IInterface mInterfaceImp = (IInterface) iBinder.queryLocalInterface(DESCRIPTOR);
            if(mInterfaceImp!=null&&mInterfaceImp instanceof mInterfaceImp){
                return (com.example.administrator.animdemo.mInterfaceImp) mInterfaceImp;
            }else {
                return new Proxy(iBinder);
            }
        }
    }

  可以看到该类并没有真正实现我们所定义的方法,而是声明为一个抽象类。这是因为我们并不知道使用者具体要怎么使用这些方法,所以把这些方法的具体实现交给使用者。
  asInterface中返回的代理类是这样的:

private static class Proxy extends Binder implements mInterfaceImp{
            private IBinder binder;

            public Proxy(IBinder binder){
                if(binder == null){
                    throw new RuntimeException("binder couldn't be null");
                }
                this.binder = binder;
            }

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

            @Override
            public void addBook(Book book) {
                Parcel parcel = Parcel.obtain();
                Parcel reply = Parcel.obtain();
                try{
                    parcel.writeInterfaceToken(DESCRIPTOR);
                    if(book!=null){
                        parcel.writeInt(1);
                        book.writeToParcel(parcel,0);
                    }else {
                        parcel.writeInt(0);
                    }

                    binder.transact(FUN_ADD_BOOK,parcel,reply,0);
                    reply.readException();
                } catch (RemoteException e) {
                    e.printStackTrace();
                } finally {
                    parcel.recycle();
                    reply.recycle();
                }
            }

            @Override
            public List<Book> getBookList() {
                Parcel parcel = Parcel.obtain();
                Parcel reply = Parcel.obtain();
                List<Book> list = null;
                try {
                    parcel.writeInterfaceToken(DESCRIPTOR);
                    binder.transact(FUN_GET_BOOK_LIST,parcel,reply,0);
                    reply.readException();
                    list = reply.createTypedArrayList(Book.CREATOR);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }finally {
                    parcel.recycle();
                    reply.recycle();
                }
                return list;
            }

            @Override
            public void registerListener(RegisterListener listener) {
                Parcel obtain = Parcel.obtain();
                Parcel reply = Parcel.obtain();
                try{
                    obtain.writeInterfaceToken(DESCRIPTOR);
                    obtain.writeStrongBinder(listener.asBinder());
                    try {
                        binder.transact(REGISTER_LISTENER,obtain,reply,0);
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                }finally {
                    obtain.recycle();
                    reply.recycle();
                }
            }

            @Override
            public void unRegisterListener(RegisterListener listener) {
                Parcel obtain = Parcel.obtain();
                Parcel reply = Parcel.obtain();
                try{
                    obtain.writeInterfaceToken(DESCRIPTOR);
                    obtain.writeStrongBinder(listener.asBinder());
                    try {
                        binder.transact(REGISTER_LISTENER,obtain,reply,0);
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                }finally {
                    obtain.recycle();
                    reply.recycle();
                }
            }

            @Override
            public IBinder asBinder() {
                return binder;
            }
        }

  代理类的方法都有具体实现,因此适合用于客户端,在具体实现中将参数序列化,然后通知binder驱动调用服务端的对应方法,也就是上面的onTransact方法。对于客户端来说,并不知道拿到的是真正的binder还是被代理的binder,他只关心调对应的方法,真正的跨进程有binder驱动来关心。
  当aidl接口作为方法的参数传递时,情况得到了反转,客户端和服务端的角色互换了。例如要实现跨进程的观察者模式。

public interface RegisterListener extends IInterface {
    ...
    void newBookArrived(Book book) throws RemoteException;
}

  先定义接口

RegisterListener.Stub registerListener = new RegisterListener.Stub() {
                 @Override
                 public void newBookArrived(Book book) throws RemoteException {
                     Log.e("-------", "------MainActivity.java:87------newBookArrived()------    " +
                             ""+book);
                 }
             };

  创建观察者,或者说创建binder。注意,这里的binder是作为服务端存在。

@Override
            public void registerListener(RegisterListener listener) {
                Parcel obtain = Parcel.obtain();
                Parcel reply = Parcel.obtain();
                try{
                    obtain.writeInterfaceToken(DESCRIPTOR);
                    obtain.writeStrongBinder(listener.asBinder());//这里形参是RegisterListener,而RegisterListener实现了IInterface,因此具有binder化的能力(实际类型其实是binder)
                    try {
                        binder.transact(REGISTER_LISTENER,obtain,reply,0);
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                }finally {
                    obtain.recycle();
                    reply.recycle();
                }
            }

@Override
        protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
            switch (code) {
                ...
                case REGISTER_LISTENER:
                    data.enforceInterface(DESCRIPTOR);
                    IBinder iBinder = data.readStrongBinder();
                    RegisterListener registerListener = RegisterListener.Stub.asInterface(iBinder);//相当于客户端,判断是否和服务端在统一进程,否则拿到代理对象。
                    this.registerListener(registerListener);
                    reply.writeNoException();
                    break;
                case UNREGISTER_LISTENER:


                    break;
            }
            return super.onTransact(code, data, reply, flags);
        }

  调用者对应的代理实现和onTransact方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值