转载请注明出处:http://blog.csdn.net/wu371894545/article/details/54962860
一、Binder机制概述
在Android开发中,很多时候我们需要用到进程间通信,所谓进程间通信,实现进程间通信的机制有很多种,比如说socket、pipe等,Android中进程间通信的方式主要有三种:
1.标准Linux Kernel IPC 接口;
2.标准D-BUS接口;
3.Binder接口。
其中,Binder机制是使用最且最被认可的,因为Binder机制有以下优点:
1.相对于其它IPC机制,Binder机制更加简洁和快速;
2.消耗的内存相对更少;
3.传统的IPC机制可能会增加进程的开销,以及出现进程过载和安全漏洞,Binder机制则有效避免和解决了这些问题。
Binder机制是Android系统的核心机制,几乎贯穿于整个Android系统,Android系统基本上可以看作是一个基于binder通信机制的C/S架构,Binder就像网络,把Android系统的各个部分连接到了一起。利用Binder机制,可以实现以下功能:
1.用驱动程序来推进进程间通信;
2.通过共享内存来提高性能;
3.为进程请求分配每个进程的线程池;
4.针对系统中的对象引入了引用计数和跨进程的对象引用映射;
5.进程间同步调用。
1. 直观来说,Binder是Android中的一个类,它继承了IBinder接口
2. 从IPC角度来说,Binder是Android中的一种跨进程通信方式,Binder还可以理解为一种虚拟的物理设备,它的设备驱动是/dev/binder,该通信方式在Linux中没有
3. 从Android Framework角度来说,Binder是ServiceManager连接各种Manager(ActivityManager、WindowManager,etc)和相应ManagerService的桥梁
4. 从Android应用层来说,Binder是客户端和服务端进行通信的媒介,当你bindService的时候,服务端会返回一个包含了服务端业务调用的Binder对象,通过这个Binder对象,客户端就可以获取服务端提供的服务或者数据,这里的服务包括普通服务和基于AIDL的服务
Android中有大量的CS(Client-Server)应用方式,这就要求Android内部提供IPC方法,而linux所支持的进程通信方式有两个问题:性能和安全性。
目前linux支持的IPC包括传统的管道,System V IPC(消息队列/共享内存/信号量),以及socket,但只有socket支持Client-Server的通信方式,由于socket是一套通用的网络通信方式,其传输效率低下切有很大的开销,比如socket的连接建立过程和中断连接过程都是有一定开销的。消息队列和管道采用存储-转发方式,即数据先从发送方缓存区拷贝到内核开辟的缓存区中,然后再从内核缓存区拷贝到接收方缓存区,至少有两次拷贝过程。共享内存虽然无需拷贝,但控制复杂,难以使用。
在安全性方面,Android作为一个开放式,拥有众多开发者的的平台,应用程序的来源广泛,确保智能终端的安全是非常重要的。终端用户不希望从网上下载的程序在不知情的情况下偷窥隐私数据,连接无线网络,长期操作底层设备导致电池很快耗尽等等。传统IPC没有任何安全措施,完全依赖上层协议来确保。首先传统IPC的接收方无法获得对方进程可靠的UID/PID(用户ID/进程ID),从而无法鉴别对方身份。Android为每个安装好的应用程序分配了自己的UID,故进程的UID是鉴别进程身份的重要标志。使用传统IPC只能由用户在数据包里填入UID/PID,但这样不可靠,容易被恶意程序利用。可靠的身份标记只有由IPC机制本身在内核中添加。其次传统IPC访问接入点是开放的,无法建立私有通道。比如命名管道的名称,system V的键值,socket的ip地址或文件名都是开放的,只要知道这些接入点的程序都可以和对端建立连接,不管怎样都无法阻止恶意程序通过猜测接收方地址获得连接。
基于以上原因,Android需要建立一套新的IPC机制来满足系统对通信方式,传输性能和安全性的要求,这就是Binder。Binder基于 Client-Server通信模式,传输过程只需一次拷贝,为发送发添加UID/PID身份,既支持实名Binder也支持匿名Binder,安全性高。
package com.ryg.chapter_2.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.ryg.chapter_2.aidl.IBookManager {
private static final java.lang.String DESCRIPTOR = "com.ryg.chapter_2.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.ryg.chapter_2.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.ryg.chapter_2.aidl.IBookManager))) {
return ((com.ryg.chapter_2.aidl.IBookManager) iin);
}
return new com.ryg.chapter_2.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.ryg.chapter_2.aidl.Book> _result = this
.getBookList();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
case TRANSACTION_addBook: {
data.enforceInterface(DESCRIPTOR);
com.ryg.chapter_2.aidl.Book _arg0;
if ((0 != data.readInt())) {
_arg0 = com.ryg.chapter_2.aidl.Book.CREATOR
.createFromParcel(data);
} else {
_arg0 = null;
}
this.addBook(_arg0);
reply.writeNoException();
return true;
}
case TRANSACTION_registerListener: {
data.enforceInterface(DESCRIPTOR);
com.ryg.chapter_2.aidl.IOnNewBookArrivedListener _arg0;
_arg0 = com.ryg.chapter_2.aidl.IOnNewBookArrivedListener.Stub
.asInterface(data.readStrongBinder());
this.registerListener(_arg0);
reply.writeNoException();
return true;
}
case TRANSACTION_unregisterListener: {
data.enforceInterface(DESCRIPTOR);
com.ryg.chapter_2.aidl.IOnNewBookArrivedListener _arg0;
_arg0 = com.ryg.chapter_2.aidl.IOnNewBookArrivedListener.Stub
.asInterface(data.readStrongBinder());
this.unregisterListener(_arg0);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements
com.ryg.chapter_2.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.ryg.chapter_2.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.ryg.chapter_2.aidl.Book> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getBookList, _data,
_reply, 0);
_reply.readException();
_result = _reply
.createTypedArrayList(com.ryg.chapter_2.aidl.Book.CREATOR);
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override
public void addBook(com.ryg.chapter_2.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();
}
}
@Override
public void registerListener(
com.ryg.chapter_2.aidl.IOnNewBookArrivedListener listener)
throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeStrongBinder((((listener != null)) ? (listener
.asBinder()) : (null)));
mRemote.transact(Stub.TRANSACTION_registerListener, _data,
_reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
@Override
public void unregisterListener(
com.ryg.chapter_2.aidl.IOnNewBookArrivedListener listener)
throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeStrongBinder((((listener != null)) ? (listener
.asBinder()) : (null)));
mRemote.transact(Stub.TRANSACTION_unregisterListener,
_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);
static final int TRANSACTION_registerListener = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
static final int TRANSACTION_unregisterListener = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3);
}
public java.util.List<com.ryg.chapter_2.aidl.Book> getBookList()
throws android.os.RemoteException;
public void addBook(com.ryg.chapter_2.aidl.Book book)
throws android.os.RemoteException;
public void registerListener(
com.ryg.chapter_2.aidl.IOnNewBookArrivedListener listener)
throws android.os.RemoteException;
public void unregisterListener(
com.ryg.chapter_2.aidl.IOnNewBookArrivedListener listener)
throws android.os.RemoteException;
}
四、Binder机制的工作流程
从上面我们可以知道Binder工作机制的流程:
1.客户端获取服务端的带来对象(proxy)。我们需要明确的是客户端进程并不能直接操作服务端中的方法,如果要操作服务端中的方法,那么有一个可行的解决方法就是在客户端建立一个服务端进程的代理对象,这个代理对象具备和服务端进程一样的功能,要访问服务端进程中的某个方法,只需要访问代理对象中对应的方法即可;
2.客户端通过调用代理对象向服务端发送请求。
3.代理对象将用户请求通过Binder驱动发送到服务器进程;
4.服务端进程处理客户端发过来的请求,处理完之后通过Binder驱动返回处理结果给客户端的服务端代理对象;
5.代理对象将请求结果进一步返回给客户端进程。
通过以上5个步骤,就完成了一次Binder通信。