Binder是一个灰常深入的话题,为什么说它深入,因为它不仅仅涉及到了应用层,还涉及到了linux驱动层,Binder的驱动层目录或者说设备驱动是/dev/binder,从一张图可以大概看出Binder总体一个工作机制。它由Client、Server、Service 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方法完成