进程间通讯是指两个进程间数据交换的过程。
线程:是cpu调度的最小单元,是一种有限的资源
进程:是指设备上的一个程序或者应用,是一个执行单元,一个进程可以包含多个线程。
Binder:是Android中的一个类实现了IBinder接口。是Android IPC跨进程通讯的一种方式,也可以理解为一种虚拟的物理设备。
1.从Framework角度说,Binder是SeiviceManager连接各种Manager(ActivityManager、WindowManage等)和相应ManagerSerivice的桥梁
2.从应用层来说它是客户端和服务端进行通信的媒介。
Binder机制在 Android中的实现主要依靠 Binder类,其实现了IBinder 接口
从三个方面介绍Binder的实现原理:
Server进程 通过Binder驱动 向 Service Manager进程 注册服务
**代码:**Server进程 创建 一个 Binder 对象:mBinder
//Server进程:
public class MyService extends Service {
private CopyOnWriteArrayList mList = new CopyOnWriteArrayList();
@Override
public void onCreate() {
super.onCreate();
mList.add(new Book(1,"三锅演绎"));
mList.add(new Book(2,"雪山飞狐"));
mList.add(new Book(3,"神雕侠侣"));
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
//服务注册后Binder驱动持有Server创建的该binder对象
return mBinder;
}
//1.创建binder对象
private Binder mBinder = new IBookManager.Stub(){
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
}
@Override
public List getBookList() throws RemoteException {
return mList;
}
@Override
public void addBook(Book book) throws RemoteException {
mList.add(book);
}
};
}
备注:
注册过程:
注册服务后,Binder驱动持有 Server进程创建的Binder实体
Client进程通过bindService()绑定Server进程中注册的service
通过service的onBinder方法返回Binder对象的代理,
1. Binder驱动为跨进程通讯做准备,实现内存映射
①在内核空间创建一块内核缓存区,接收缓存区,
②实现地址映射关系:根据ServiceManager里的Server信息找到对应的Server进程
实现内核缓存区和Server进程的用户空间地址同时映射到同一个接收缓存区,由系统实现
2. Client进程将参数数据发送到Server进程
步骤:
Client进程通过系统调用copy_from_user
发送数据到内核空间中的缓存区,基于之前建立的映射关系相当于发送到Server进程;
实现:
Client 进程将需要发送的数据写入到Parcel对象中
传递的数据包括目标方法标识符、序列化对象(存放了目标方法的参数、方法对象标识符)、存放执行结果的reply参数
通过调用代理对象的transact方法将数据发送到Binder驱动
Binder驱动根据代理对象找到对应的Binder对象所在的Server进程
Binder驱动把数据发送到Server进程中,并通知Server进程执行解包
3. Server进程根据Client进程要求调用目标方法,并把目标方法返回结果返回给Clicent
Client进程通过系统调用copy_to_user 从内核缓存接收Server进程返回的数据
下面我们从代码上解释一下2和3:
//Client 进程
public class MyAIDLActivity extends Activity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_aidl);
initWindows();
Intent intent = new Intent(this, MyService.class);
bindService(intent,myServiceConn, Context.BIND_AUTO_CREATE);
}
ServiceConnection myServiceConn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder binder) {
//拿到服务端代理对象,为所欲为
IBookManager myBookManager = IBookManager.Stub.asInterface(binder);
try {
myBookManager.addBook(new Book(4,"西游记啊"));
myBookManager.addBook(new Book(5,"西游记啊"));
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onDestroy() {
unbindService(myServiceConn);
super.onDestroy();
}
}
//IBookManager.java
public interface IBookManager extends IInterface {
void addBook(Book var1) throws RemoteException;
public abstract static class Stub extends Binder implements com.dkp.viewdemo.ipc.IBookManager {
.....
}
}
//IBookManager.java 中的 Sub中的 Binder 代理类
private static class Proxy implements com.dkp.viewdemo.ipc.IBookManager {
private IBinder mRemote;
Proxy(IBinder remote) {
this.mRemote = remote;
}
public IBinder asBinder() {
return this.mRemote;
}
public String getInterfaceDescriptor() {
return "com.dkp.viewdemo.ipc.IBookManager";
}
public void addBook(Book book) throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
try {
_data.writeInterfaceToken("com.dkp.viewdemo.ipc.IBookManager");
if(book != null) {
_data.writeInt(1);
book.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
//目标方法标识符、_data:Parcel存放目标方法的参数、方法对象标识符 reply:存放执行结果的参数
1.调用Binder的transact
this.mRemote.transact(1, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
}
//IBookManager.java 中的Binder类 Stub
public abstract static class Stub extends Binder implements com.dkp.viewdemo.ipc.IBookManager {
private static final String DESCRIPTOR = “com.dkp.viewdemo.ipc.IBookManager”;//给binder添加一个标记,方便用的时候查找对应的binder
static final int TRANSACTION_basicTypes = 1;
static final int TRANSACTION_getBookList = 2;
static final int TRANSACTION_addBook = 3;
public Stub() {
this.attachInterface(this, "com.dkp.viewdemo.ipc.IBookManager");
}
public static com.dkp.viewdemo.ipc.IBookManager asInterface(IBinder obj) {
if(obj == null) {
return null;
} else {
IInterface iin = obj.queryLocalInterface("com.dkp.viewdemo.ipc.IBookManager");
return (IBookManager)(iin != null && iin instanceof IBookManager ?(IBookManager)iin:new com.dkp.viewdemo.ipc.IBookManager.Stub.Proxy(obj));
}
}
public IBinder asBinder() {
return this;
}
//由代理类调用,并传递参数过来
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
switch(code) {//跟code判断执行对相应的方法
case 1:
data.enforceInterface("com.dkp.viewdemo.ipc.IBookManager");
Book _arg0;
if(0 != data.readInt()) {
_arg0 = (Book)Book.CREATOR.createFromParcel(data);
} else {
_arg0 = null;
}
//2.this是Server的binder对象,调用addBook
this.addBook(_arg0);
reply.writeNoException();
return true;
case 1598968902:
reply.writeString("com.dkp.viewdemo.ipc.IBookManager");
return true;
default:
return super.onTransact(code, data, reply, flags);
}
}
private static class Proxy implements com.dkp.viewdemo.ipc.IBookManager {
......
}
}
//Server端的Binder
private Binder mBinder = new IBookManager.Stub(){
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
}
@Override
public List getBookList() throws RemoteException {
return mList;
}
//3.服务端transact里this.addBook(_arg0);会调用到这里
@Override
public void addBook(Book book) throws RemoteException {
mList.add(book);
}
};
总结:声明服务端,在服务端里创建一个Binder,binder创建的时候会通过attachInterface接口将binder和binder描述添加到Binder驱动中,客户端注册服务,Binder将注册请求转发到ServiceManager,ServiceManager保存了Service的信息,客户端需要通信时,通过bindService 在onServiceConnected方法里得到服务端binder,然后通过Binder 的 asInterface方法拿到服务端Binder的代理对象,代理对象内持有服务端的应用,使用这个代理对象执行操作时会调用Binder驱动的onTransact,然后调用服务端Binder的onTransact方法,传递目标方法标识符、_data:Parcel存放目标方法的参数、方法对象标识符 reply:存放执行结果的参数给服务端的Binder,transact里通过方法标识符调用服务端对应的方法,通过 reply.writeTypedList();等方法把结果返回。
学习参考:
https://www.jianshu.com/p/4ee3fd07da14