进程间通讯总结
进程间通讯是指两个进程间数据交换的过程。
1.进程与线程区别
线程:是cpu调度的最小单元,是一种有限的资源
进程:是指设备上的一个程序或者应用,是一个执行单元,一个进程可以包含多个线程。
Binder:是Android中的一个类实现了IBinder接口。是Android IPC跨进程通讯的一种方式,也可以理解为一种虚拟的物理设备。
1.从Framework角度说,Binder是SeiviceManager连接各种Manager(ActivityManager、WindowManage等)和相应ManagerSerivice的桥梁
2.从应用层来说它是客户端和服务端进行通信的媒介。
2.跨进程通讯底层原理
- Android系统是基于Linux系统的,一个进程可以分为用户空间和内核空间,用户空间是相互独立的,内核空间系统共享的。
- 首先Binder驱动在内核空间创建一个数据接收缓冲区
- 接着在内核空间开辟一块内核缓存区,建立内核缓存区和内核中数据接收缓存区之间的映射关系,以及内核中数据接收缓存区和接收进程用户空间地址的映射关系
- 发送方进程通过系统调用copyfromuser将数据copy到内核中的内核缓存区,由于内核缓存区和接收进程的用户空间存在内存映射因此也就相当于把数据发送到了接收进程的用户空间,这样便完成了一次进程间的通信。
3.跨进程实现原理
Binder机制在 Android中的实现主要依靠 Binder类,其实现了IBinder 接口
从三个方面介绍Binder的实现原理:
1.注册服务
Server进程 通过Binder驱动 向 Service Manager进程 注册服务
**代码:**Server进程 创建 一个 Binder 对象:mBinder
//Server进程:
public class MyService extends Service {
private CopyOnWriteArrayList<Book> mList = new CopyOnWriteArrayList<Book>();
@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<Book> getBookList() throws RemoteException {
return mList;
}
@Override
public void addBook(Book book) throws RemoteException {
mList.add(book);
}
};
}
备注:
- Binder 实体是 Server进程 在 Binder 驱动中的存在形式
- 该对象保存 Server 和 ServiceManager 的信息(保存在内核空间中)
- Binder 驱动通过 内核空间的Binder 实体 找到用户空间的Server对象
注册过程:
- Server进程向Binder驱动发起服务注册请求 (服务注册)
- Binder驱动将注册转发请求转发给SerViceManager
- ServiceManager 进程添加该Server进程,此时ServiceManager已经拥有Server进程的信息
注册服务后,Binder驱动持有 Server进程创建的Binder实体
2.获取服务
- Client向Binder驱动发起获取服务的请求,并传递要获取的服务名称。
Client进程通过bindService()绑定Server进程中注册的service
- Binder驱动请求转发给ServiceManager,ServiceManager查找到Client需要的Server对应的Binder对象的引用信息,返回给Binder驱动
通过service的onBinder方法返回Binder对象的代理,
- Binder驱动将上述Binder代理对象返回给Client(此时Client与Server进程已经建立了连接)
3.使用服务
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();
}
}
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<Book> 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();等方法把结果返回。