Android Binder通信研习录

Android Binder通信研习录

Binder作为Android进程间通信最重要的工具,一直以来困扰着我,这两天翻看了几位大神的博客,基本上都是从底层+应用层完全讲解,奈何本人对Jni不是很熟悉,所以忽略了底层的原理解析,现将应用层的原理整理下来,方便日后查看,如果有什么地方不准确,欢迎阅览者指出。

相关概念解析

  1. IInterface:系统提供的一个接口,所有可以在Binder中传输的接口都必须继承该接口;
  2. AIDL文件:通过该文件,可以自动生成一个固定格式的Binder类,可以理解为系统为我们提供的实现Binder的工具;

实现过程

既然AIDL文件能够自动生成一个Binder类,那么我们就先获得一个Binder对象;

  • 准备Book.java文件,实现Parcelable接口:
public class Book implements Parcelable {
    public int bookId;
    public String bookName;
    public Book(int bookId, String bookName) {
        this.bookId = bookId;
        this.bookName = bookName;
    }
    protected Book(Parcel in) {
        bookId = in.readInt();
        bookName = in.readString();
    }
    public static final Creator<Book> CREATOR = new Creator<Book>() {
        @Override
        public Book createFromParcel(Parcel in) {
            return new Book(in);
        }

        @Override
        public Book[] newArray(int size) {
            return new Book[size];
        }
    };
    @Override
    public int describeContents() {
        return 0;
    }
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(bookId);
        dest.writeString(bookName);
    }
}
  • 准备一个AIDL文件Book.aidl,用于声明经过序列化的Book.java:
package heyha.nj.com.binder;
import statements
parcelable Book;
  • 编写AIDL接口文件IBookManager.aidl,注意要导入相关类:
import heyha.nj.com.tablayout.Book;
interface IBookManager {
            List<Book> getBookList();
            void addBook(in Book book);
}

至此,编译程序,就会自动生成相应的Binder类,如下:

public interface IBookManager extends android.os.IInterface {
    /**
     * Local-side IPC implementation stub class.
     */
    public static abstract class Stub extends android.os.Binder implements heyha.nj.com.tablayout.IBookManager {
        private static final java.lang.String DESCRIPTOR = "heyha.nj.com.tablayout.IBookManager";
        /**
         * Construct the stub at attach it to the interface.
         */
        public Stub() {
            this.attachInterface(this, DESCRIPTOR);
        }
        /**
         * Cast an IBinder object into an heyha.nj.com.tablayout.IBookManager interface,
         * generating a proxy if needed.
         */
        public static heyha.nj.com.tablayout.IBookManager asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof heyha.nj.com.tablayout.IBookManager))) {
                return ((heyha.nj.com.tablayout.IBookManager) iin);
            }
            return new heyha.nj.com.tablayout.IBookManager.Stub.Proxy(obj);
        }
        @Override
        public android.os.IBinder asBinder() {
            return this;
        }
        @Override
        public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
            switch (code) {
                case INTERFACE_TRANSACTION: {
                    reply.writeString(DESCRIPTOR);
                    return true;
                }
                case TRANSACTION_getBookList: {
                    data.enforceInterface(DESCRIPTOR);
                    java.util.List<heyha.nj.com.tablayout.Book> _result = this.getBookList();
                    reply.writeNoException();
                    reply.writeTypedList(_result);
                    return true;
                }
                case TRANSACTION_addBook: {
                    data.enforceInterface(DESCRIPTOR);
                    heyha.nj.com.tablayout.Book _arg0;
                    if ((0 != data.readInt())) {
                        _arg0 = heyha.nj.com.tablayout.Book.CREATOR.createFromParcel(data);
                    } else {
                        _arg0 = null;
                    }
                    this.addBook(_arg0);
                    reply.writeNoException();
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }
        private static class Proxy implements heyha.nj.com.tablayout.IBookManager {
            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 java.util.List<heyha.nj.com.tablayout.Book> getBookList() throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                java.util.List<heyha.nj.com.tablayout.Book> _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.createTypedArrayList(heyha.nj.com.tablayout.Book.CREATOR);
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
            @Override
            public void addBook(heyha.nj.com.tablayout.Book book) throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    if ((book != null)) {
                        _data.writeInt(1);
                        book.writeToParcel(_data, 0);
                    } else {
                        _data.writeInt(0);
                    }
                    mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
                    _reply.readException();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }
        }
        static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
        static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
    }
    public java.util.List<heyha.nj.com.tablayout.Book> getBookList() throws android.os.RemoteException;
    public void addBook(heyha.nj.com.tablayout.Book book) throws android.os.RemoteException;
}

下面详细说明该类的内容:
首先,它声明了两个方法getBookList和addBook,显然这是我们在aidl文件中声明的方法,同时声明了两个id分别标志这两个方法,这两个id标识transact过程中客户端请求的是哪个方法;接着,它声明了一个内部类Stub,这个Stub实现了它本身,所以Stub也是一个Binder类;根据asInterface方法的实现,如果客户端和服务端位于一个进程中,那该方法返回的是它本身(IBookManager),否则返回的是Stub的内部类Proxy,据此可知,如果客户端跨进程访问,那么方法调用是通过Proxy实现的;那么这个类内部的每个方法的含义是怎样的呢?

  • asInterface(android.os.IBinder obj):用于将服务端返回的Binder对象转化为客户端需要的AIDL接口类型的对象;该方法区分进程,即客户端和服务端位于同一进程,返回服务端的Stub对象本身,否则返回经过系统封装的Stub.Proxy对象;
  • asBinder():返回服务端的Stub对象;
  • onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags):该方法位于服务端的Binder线程池中,用于处理客户端和服务端位于同一进程时的方法调用;如果返回false,那么客户端请求失败;
  • Proxy.getBookList():该方法中的mRemote.transact()位于服务端的Binder线程池中用于处理客户端和服务端位于不同进程时的方法调用,注意,调用该方法的客户端和服务端是同步的,所以不能在UI线程中调用该方法;

至此,Binder的应用层实现完成;但是,如果服务端由于某种原因关闭,Binder连接断裂,那么客户端调用方法就会失败,客户端如何在Binder连接断裂时接到通知然后重新发起请求呢?好在Binder提供了linkToDeath方法和unlinkToDeath方法,在客户端为Binder设置linkToDeath方法就可以在Binder断裂时接到通知,重新发起请求需要自己去实现。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值