浅谈Android中的Binder机制
2016-06-07 10:54
645 查看
Binder是一个灰常深入的话题,为什么说它深入,因为它不仅仅涉及到了应用层,还涉及到了linux驱动层,Binder的驱动层目录或者说设备驱动是/dev/binder,从一张图可以大概看出Binder总体一个工作机制。它由Client、Server、Service
Manager和驱动程序Binder四个组件构成。
![](https://img-blog.csdn.net/20160607104705099)
从IPC角度来看,这张图表示Binder是一种跨进程通信方式,Binder也可以理解为一种虚拟的物理设备,它的设备驱动是/dev/binder,从Android framework角度来说,Binder是Service Manager连接各种Manager(ActivityManager WindowManager等等)和相应ManagerService的桥梁,当然这是从源码角度,从Android应用层来说,Binder是客户端和服务端进行通信的媒介,当bindService的时候,服务端会返回一个包含了服务端业务的Binder对象,通过这个Binder对象,客户端可以获取服务端提供的服务或者数据,这里的服务包括普通服务和基于AIDL的服务。
其中Service Manager,它是整个Binder机制的守护进程,用来管理开发者创建的各种Server,并且向Client提供查询Server远程接口的功能。Service Manager组件是用来管理Server并且向Client提供查询Server远程接口的功能,那么,Service Manager就必然要和Server以及Client进行通信了。我们知道,Service
Manger、Client和Server三者分别是运行在独立的进程当中,这样它们之间的通信也属于进程间通信了,而且也是采用Binder机制进行进程间通信,因此,Service Manager在充当Binder机制的守护进程的角色的同时,也在充当Server的角色,然而,它是一种特殊的Server,Service Manager是成为Android进程间通信(IPC)机制Binder守护进程的过程是这样的:
1. 打开/dev/binder文件:open("/dev/binder", O_RDWR);
2. 建立128K内存映射:mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
3. 通知Binder驱动程序它是守护进程:binder_become_context_manager(bs);
4. 进入循环等待请求的到来:binder_loop(bs, svcmgr_handler);
我个人从AIDL方面来说一下我对Binder机制的理解。也就是上面所说的Android应用层角度来分析Binder机制。
新建包com.qian.aidl,然后在包中新建三个文件,Book.java Book.aidl IBookManager.aidl代码如下
Book.java
Bool.aidl
IBookManager.aidl
上面三个文件中,Book.java是一个表示图书信息的类,它实现了Parceable接口。Book.aidl是Book类在aidl中的声明。IBookManager.aidl是定义的一个接口,里面有两个方法,主要用于远程调用,分别是getBookList和addBook,其中getBookList用于从远程服务端获取图书列表,addBook用于添加,此时在gen目录下已经自动生成了一个类 IBookManager.java。
代码如下,经过了稍微的格式转换。
代码结构大概是,首先是IBookManager类继承了IIterface这个接口,接着里面直接包含了一个内部类Stub,Stub里面又包含了一个Proxy类和Stub类中的一些方法和变量声明。变量为DESCRIPTOR,方法有asInterface,asBinder,onTransact。
OK,结构分析完了,下面看是分析Binder机制。Binder机制又和上述方法asInterface,asBinder,onTransact息息相关。
DESCRIPTOR
Binder的唯一标识,一般用当前Binder的类名表示,比如上述代码
asInterface(android.os.IBinder obj)
用于将服务端的Binder对象转换为客户端所需要的AIDL接口类型的对象,这种转换过程又是区分进程的,如果客户端和服务端位于同一进程,那么此方法返回的就是服务端的Stub对象本身(Stub——>extends
Binder)否则返回Stub.Proxy对象。也是一个Binder对象。
可以这么说,远程请求返回的是Binder对象,而Binder对象中则封装了我们所请求需要的一些参数在里面,通过强制类型转换即可获得相对的对象。
asBinder()
此方法用于返回当前的Binder对象。
onTransact
这个方法运行在服务端的Binder线程池中,当客户端发起跨进程请求时,远程请求会通过系统底层封装后交由此方法处理。该方法的原型为:
public boolean onTransact(intcode, android.os.Parceldata,
android.os.Parcel reply, int
flags) throws android.os.RemoteException
服务端通过code可以确定客户端所请求的目标方法是什么,接着从data中取出目标方法所需的参数(如果目标方法有参数的话),然后执行目标方法。当目标方法执行完毕后,就向reply中写入返回值(如果目标方法有返回值的话),onTransact方法的执行过程就是这样的。需要注意的是,如果此方法返回false,那么客户端的请求会失败,因此我们可以利用这个特性来做权限验证,毕竟我们也不希望随便一个进程都能远程调用我们的服务。
Proxy#getBookList
这个方法运行在客户端,当客户端远程调用此方法时,他的内部实现是这样的:
1)首先创建该方法所需要的输入型Parce对象_data、输出型Parce对象_reply和返回值对象List;
2)然后把该方法的参数信息写入_data中(如果有参数)
3)接着调用transact方法来发起RPC(远程过程调用)请求,同时当前线程挂起;
4)然后服务端的onTransact方法会被调用,直到RPC过程返回,客户端挂起的线程继续执行,并从_reply中取出RPC过程的返回结果;
5)最后返回_reply的数据。
Proxy#addBook
这个方法运行在客户端,它的执行过程和getBookList是一样的,addBookList没有返回值,所以它不需要从_reply中取出结果。
IBookManager.aidl中声明了两个整形的变量:
自动生成的IBookManager.java继承了IInterface这个接口,IIterface这个接口的源码中有这样一句注释,“ase class for Binder interfaces”,所有Binder接口的基类,那么首先它本身就是一个Binder对象,内部类Stub直接继承Binder,所以Stub也是Binder对象,Stub.Proxy继承了IBookManager,所以Stub.Proxy也是一个Binder对象。
当客户端和服务端位于同一进程中时,方法调用不会走跨进程的transact过程,当跨进程方法调用时,需要走transact过程,这个逻辑由Stub.Proxy来完成。
Binder的工作机制图如下所示:
![](https://img-blog.csdn.net/20160607211105565)
Binder返回数据唤醒Clinet,返回的是Bidner对象,但是需要转换AIDL接口类型的对象,这个过程由asInterface方法完成
Manager和驱动程序Binder四个组件构成。
从IPC角度来看,这张图表示Binder是一种跨进程通信方式,Binder也可以理解为一种虚拟的物理设备,它的设备驱动是/dev/binder,从Android framework角度来说,Binder是Service Manager连接各种Manager(ActivityManager WindowManager等等)和相应ManagerService的桥梁,当然这是从源码角度,从Android应用层来说,Binder是客户端和服务端进行通信的媒介,当bindService的时候,服务端会返回一个包含了服务端业务的Binder对象,通过这个Binder对象,客户端可以获取服务端提供的服务或者数据,这里的服务包括普通服务和基于AIDL的服务。
其中Service Manager,它是整个Binder机制的守护进程,用来管理开发者创建的各种Server,并且向Client提供查询Server远程接口的功能。Service Manager组件是用来管理Server并且向Client提供查询Server远程接口的功能,那么,Service Manager就必然要和Server以及Client进行通信了。我们知道,Service
Manger、Client和Server三者分别是运行在独立的进程当中,这样它们之间的通信也属于进程间通信了,而且也是采用Binder机制进行进程间通信,因此,Service Manager在充当Binder机制的守护进程的角色的同时,也在充当Server的角色,然而,它是一种特殊的Server,Service Manager是成为Android进程间通信(IPC)机制Binder守护进程的过程是这样的:
1. 打开/dev/binder文件:open("/dev/binder", O_RDWR);
2. 建立128K内存映射:mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
3. 通知Binder驱动程序它是守护进程:binder_become_context_manager(bs);
4. 进入循环等待请求的到来:binder_loop(bs, svcmgr_handler);
我个人从AIDL方面来说一下我对Binder机制的理解。也就是上面所说的Android应用层角度来分析Binder机制。
新建包com.qian.aidl,然后在包中新建三个文件,Book.java Book.aidl IBookManager.aidl代码如下
Book.java
package com.qian.aidl; import android.os.Parcel; import android.os.Parcelable; public class Book implements Parcelable { public int bookId; public String bookName; public Book() { } public Book(int bookId, String bookName) { this.bookId = bookId; this.bookName = bookName; } public int describeContents() { return 0; } public void writeToParcel(Parcel out, int flags) { out.writeInt(bookId); out.writeString(bookName); } public static final Parcelable.Creator<Book> CREATOR = new Parcelable.Creator<Book>() { public Book createFromParcel(Parcel in) { return new Book(in); } public Book[] newArray(int size) { return new Book[size]; } }; private Book(Parcel in) { bookId = in.readInt(); bookName = in.readString(); } @Override public String toString() { return String.format("[bookId:%s, bookName:%s]", bookId, bookName); } }
Bool.aidl
package com.qian.aidl; parcelable Book;
IBookManager.aidl
package com.qian.aidl; import com.qian.aidl.Book; interface IBookManager { List<Book> getBookList(); void addBook(in Book book); }
上面三个文件中,Book.java是一个表示图书信息的类,它实现了Parceable接口。Book.aidl是Book类在aidl中的声明。IBookManager.aidl是定义的一个接口,里面有两个方法,主要用于远程调用,分别是getBookList和addBook,其中getBookList用于从远程服务端获取图书列表,addBook用于添加,此时在gen目录下已经自动生成了一个类 IBookManager.java。
代码如下,经过了稍微的格式转换。
package com.qian.aidl; public interface IBookManager extends android.os.IInterface { /** Local-side IPC implementation stub class. */ public static abstract class Stub extends android.os.Binder implements com.qian.aidl.IBookManager { private static final java.lang.String DESCRIPTOR = "com.qian.aidl.IBookManager"; /** Construct the stub at attach it to the interface. */ public Stub() { this.attachInterface(this, DESCRIPTOR); } /** * Cast an IBinder object into an com.ryg.chapter_2.aidl.IBookManager interface, * generating a proxy if needed. */ public static com.qian.aidl.IBookManager asInterface(android.os.IBinder obj) { if ((obj==null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin!=null)&&(iin instanceof com.qian.aidl.IBookManager))) { return ((com.qian.aidl.IBookManager)iin); } return new com.qian.aidl.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<com.qian.aidl.Book> _result = this.getBookList(); reply.writeNoException(); reply.writeTypedList(_result); return true; } case TRANSACTION_addBook: { data.enforceInterface(DESCRIPTOR); com.qian.aidl.Book _arg0; if ((0!=data.readInt())) { _arg0 = com.qian.aidl.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 com.qian.aidl.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<com.qian.aidl.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<com.qian.aidl.Book> _result; try { _data.writeInterfaceToken(DESCRIPTOR); mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0); _reply.readException(); _result = _reply.createTypedArrayList(com.qian.aidl.Book.CREATOR); } finally { _reply.recycle(); _data.recycle(); } return _result; } @Override public void addBook(com.qian.aidl.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<com.qian.aidl.Book> getBookList() throws android.os.RemoteException; public void addBook(com.qian.aidl.Book book) throws android.os.RemoteException; }
代码结构大概是,首先是IBookManager类继承了IIterface这个接口,接着里面直接包含了一个内部类Stub,Stub里面又包含了一个Proxy类和Stub类中的一些方法和变量声明。变量为DESCRIPTOR,方法有asInterface,asBinder,onTransact。
OK,结构分析完了,下面看是分析Binder机制。Binder机制又和上述方法asInterface,asBinder,onTransact息息相关。
DESCRIPTOR
Binder的唯一标识,一般用当前Binder的类名表示,比如上述代码
private static final java.lang.String DESCRIPTOR = "com.qian.aidl.IBookManager";
asInterface(android.os.IBinder obj)
用于将服务端的Binder对象转换为客户端所需要的AIDL接口类型的对象,这种转换过程又是区分进程的,如果客户端和服务端位于同一进程,那么此方法返回的就是服务端的Stub对象本身(Stub——>extends
Binder)否则返回Stub.Proxy对象。也是一个Binder对象。
可以这么说,远程请求返回的是Binder对象,而Binder对象中则封装了我们所请求需要的一些参数在里面,通过强制类型转换即可获得相对的对象。
asBinder()
此方法用于返回当前的Binder对象。
onTransact
这个方法运行在服务端的Binder线程池中,当客户端发起跨进程请求时,远程请求会通过系统底层封装后交由此方法处理。该方法的原型为:
public boolean onTransact(intcode, android.os.Parceldata,
android.os.Parcel reply, int
flags) throws android.os.RemoteException
服务端通过code可以确定客户端所请求的目标方法是什么,接着从data中取出目标方法所需的参数(如果目标方法有参数的话),然后执行目标方法。当目标方法执行完毕后,就向reply中写入返回值(如果目标方法有返回值的话),onTransact方法的执行过程就是这样的。需要注意的是,如果此方法返回false,那么客户端的请求会失败,因此我们可以利用这个特性来做权限验证,毕竟我们也不希望随便一个进程都能远程调用我们的服务。
Proxy#getBookList
这个方法运行在客户端,当客户端远程调用此方法时,他的内部实现是这样的:
1)首先创建该方法所需要的输入型Parce对象_data、输出型Parce对象_reply和返回值对象List;
2)然后把该方法的参数信息写入_data中(如果有参数)
3)接着调用transact方法来发起RPC(远程过程调用)请求,同时当前线程挂起;
4)然后服务端的onTransact方法会被调用,直到RPC过程返回,客户端挂起的线程继续执行,并从_reply中取出RPC过程的返回结果;
5)最后返回_reply的数据。
Proxy#addBook
这个方法运行在客户端,它的执行过程和getBookList是一样的,addBookList没有返回值,所以它不需要从_reply中取出结果。
IBookManager.aidl中声明了两个整形的变量:
static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);这两个id用于表示在transact过程中客户端请求的是哪个方法。
自动生成的IBookManager.java继承了IInterface这个接口,IIterface这个接口的源码中有这样一句注释,“ase class for Binder interfaces”,所有Binder接口的基类,那么首先它本身就是一个Binder对象,内部类Stub直接继承Binder,所以Stub也是Binder对象,Stub.Proxy继承了IBookManager,所以Stub.Proxy也是一个Binder对象。
当客户端和服务端位于同一进程中时,方法调用不会走跨进程的transact过程,当跨进程方法调用时,需要走transact过程,这个逻辑由Stub.Proxy来完成。
Binder的工作机制图如下所示:
Binder返回数据唤醒Clinet,返回的是Bidner对象,但是需要转换AIDL接口类型的对象,这个过程由asInterface方法完成
相关文章推荐
- 解决ScrollView下嵌套ListView、GridView中内容显示不全的问题
- Android的Scroller介绍
- Android_Intent_note
- Android MediaCodec h264硬件编码
- android 显示清除缓存
- 升级android studio后编译的应用短暂白屏
- 读取AXML二进制流修改DEMO
- android收集bug(异常)信息,上传至服务器
- android动画详解
- Android开发框架之自定义ZXing二维码扫描界面并解决取景框拉伸问题
- Android使用EventBus框架优化代码逻辑
- android数据库、安卓数据库读写
- [Android] 数据存储五种方式使用与总结
- Android热点连接管理(一)
- Android自定义View详解
- Androidt退出登录时弹出确认对话框
- Android中Edittext的自定义文本框边线
- 再读epoll有感
- android之ViewFlipper实现左右滑动动画效果
- Android DynamicGrid:拖曳交换位置