大家都知道,如果被问到binder,第一时间都会答是用来进程间通讯。那到底是怎么通讯的?我们一般用AIDL来实现,如果你完全没用过AIDL,可以先看这个:AIDL简单实现进程间通讯
那么,问题来了。
问题一:binder是什么?
①内核层的binder驱动 ②Binder的Java类
通过实现Binder的IBinder接口,可以获得进程间通讯的能力。
问题二:binder是用于进程间通讯,用在哪些地方,为什么要用?
如果一个APP分配多个进程,可以达到扩大内存的效果;而且一个进程的崩溃,也不会造成APP直接崩溃,隔离了部分的风险。
一般放到另一个进程的功能点有:webview、图片下载、文件下载处理等。
①共享内存,可以理解为线程安全,由于涉及锁和原子性等问题,会导致难以操控。
②socket,性能上,会比binder消耗得多。
③在手机端,由于binder可以为访问的APP分配UID,自己的服务进程也支持是否给外部调用,安全性非常好。
binder是怎么做到的进程间通讯?
①发送方通过binder协议,打包好数据,通过copy_from_user把数据拷贝一次到内核地址空间。
②利用mmap方法,使得内核空间的地址和接收方的空间地址,都映射到同一个物理内存中。
由于内核空间和接收方的进程空间,都指向了同一个物理内存,所以当发送方发送数据时,数据不需要再一次从内内核中copy到接收方中,从而省掉了一次数据的拷贝。
举个例子:平常我们的把数据写到本地文件的功能,其实是分为2步的,第一步是把数据传输到内核层,然后内核层再把数据传输到本地文件,这种就是经历过2次的数据copy。
而binder就不需要,由于mmap的处理,等于我们可以直接把用户层的东西,只传一次给内核层,就达到了我们想要的效果。
AIDL实现原理
/*
* This file is auto-generated. DO NOT MODIFY.
*/
package com.tonydash.aidl.bean;
public interface IPersonAidlInterface extends android.os.IInterface
{
/** Default implementation for IPersonAidlInterface. */
public static class Default implements com.tonydash.aidl.bean.IPersonAidlInterface
{
@Override public void addPersonIn(com.tonydash.aidl.bean.Person person) throws android.os.RemoteException
{
}
@Override
public android.os.IBinder asBinder() {
return null;
}
}
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.tonydash.aidl.bean.IPersonAidlInterface
{
private static final java.lang.String DESCRIPTOR = "com.tonydash.aidl.bean.IPersonAidlInterface";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.tonydash.aidl.bean.IPersonAidlInterface interface,
* generating a proxy if needed.
*/
public static com.tonydash.aidl.bean.IPersonAidlInterface asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.tonydash.aidl.bean.IPersonAidlInterface))) {
return ((com.tonydash.aidl.bean.IPersonAidlInterface)iin);
}
return new com.tonydash.aidl.bean.IPersonAidlInterface.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
{
java.lang.String descriptor = DESCRIPTOR;
switch (code)
{
case INTERFACE_TRANSACTION:
{
reply.writeString(descriptor);
return true;
}
case TRANSACTION_addPersonIn:
{
data.enforceInterface(descriptor);
com.tonydash.aidl.bean.Person _arg0;
if ((0!=data.readInt())) {
_arg0 = com.tonydash.aidl.bean.Person.CREATOR.createFromParcel(data);
}
else {
_arg0 = null;
}
this.addPersonIn(_arg0);
reply.writeNoException();
return true;
}
default:
{
return super.onTransact(code, data, reply, flags);
}
}
}
private static class Proxy implements com.tonydash.aidl.bean.IPersonAidlInterface
{
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 void addPersonIn(com.tonydash.aidl.bean.Person person) 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 ((person!=null)) {
_data.writeInt(1);
person.writeToParcel(_data, 0);
}
else {
_data.writeInt(0);
}
boolean _status = mRemote.transact(Stub.TRANSACTION_addPersonIn, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
getDefaultImpl().addPersonIn(person);
return;
}
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
public static com.tonydash.aidl.bean.IPersonAidlInterface sDefaultImpl;
}
static final int TRANSACTION_addPersonIn = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
public static boolean setDefaultImpl(com.tonydash.aidl.bean.IPersonAidlInterface impl) {
if (Stub.Proxy.sDefaultImpl == null && impl != null) {
Stub.Proxy.sDefaultImpl = impl;
return true;
}
return false;
}
public static com.tonydash.aidl.bean.IPersonAidlInterface getDefaultImpl() {
return Stub.Proxy.sDefaultImpl;
}
}
public void addPersonIn(com.tonydash.aidl.bean.Person person) throws android.os.RemoteException;
}
这个文件是Androidstudio帮我们自动生成的,代码很多,但需要注意的有几点:
①Stub类继承Binder类,并实现我们自己自定义的aidl接口类。
②asInterface方法,会判断是否同一个进程,同进程直接返回binder,不同进程就创建一个代理类。
③代理类主要是要来实现我们自定义的接口方法的,通过mRemote.transact方法,打包数据,发送给内核层的binder驱动。
④mRemote.transact调用后,线程会挂起,等待服务端返回。
⑤Stub类中有onTransact方法,就是用于接收消息并分发的。