简介
Binder 是一种进程间通信机制,实现进程间通讯。
比较
Linux内核提供的IPC机制:管道、Socket 、共享内存、消息队列等。
共享内存使多个进程可以访问同一个内存空间,管理混乱;
管道耗费性能,需要两次拷贝数据(copy_from_user从客户端拷贝数据到内核空间、copy_to_user从内核空间拷贝数据到服务端);
Socket适合用于网络通讯,传输效率低,开销大,但是不适用于进程间通讯。(2次数据拷贝)
Binder通过驱动在内核空间拷贝数据,不需要额外的同步处理。只要进行一次数据拷贝,性能仅次于共享内存。
进程的 UID 是鉴别进程身份的重要标志。Binder支持通讯双方身份校验(UID/PID),安全性较高。
注:传统的进程通讯方式没有对通讯双方的身份做严格的验证,如Socket通讯。
Binder既支持实名Binder也支持匿名Binder。
角色
Binder基于C/S架构。实现面向对象的调用方式,在使用Binder时,就和调用一个本地对象实例一样。
Server(用户空间):服务端
Client(用户空间):客户端
ServiceManager(用户空间):Server和Client之间的桥梁。Client可以通过ServiceManager获得Server中Binder实体的引用。Server将自己的Binder引用注册到ServiceManager中,Client通过特定的key从ServiceManager中获取Server的Binder引用。
Binder驱动(内核空间):一种虚拟设备驱动。连接Server、Client和ServiceManager的桥梁,实现进程之间 Binder 通信(内存映射、调用mmap()函数))。
对象
IBinder :实现跨进程传输的能力;
IInterface:Server端提供的功能;
Binder:java层Binder类;
Binder本地对象、BinderProxy本地代理(Binder内部类)。Binder和BinderProxy都继承自IBinder,Binder驱动自动完成Binder与BinderProxy的转换。
Stub(抽象类):继承Binder,实现IInterface接口
public interface ILoginInterface extends android.os.IInterface
{
/** Default implementation for ILoginInterface. */
public static class Default implements com.sc.binder.test.ILoginInterface
{
@Override public void login() throws android.os.RemoteException
{
}
@Override public void loginCallback(boolean res, java.lang.String user) 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.sc.binder.test.ILoginInterface
{
private static final java.lang.String DESCRIPTOR = "com.sc.binder.test.ILoginInterface";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.sc.binder.test.ILoginInterface interface,
* generating a proxy if needed.
*/
public static com.sc.binder.test.ILoginInterface asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.sc.binder.test.ILoginInterface))) {
return ((com.sc.binder.test.ILoginInterface)iin);
}
return new com.sc.binder.test.ILoginInterface.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_login:
{
data.enforceInterface(descriptor);
this.login();
reply.writeNoException();
return true;
}
case TRANSACTION_loginCallback:
{
data.enforceInterface(descriptor);
boolean _arg0;
_arg0 = (0!=data.readInt());
java.lang.String _arg1;
_arg1 = data.readString();
this.loginCallback(_arg0, _arg1);
reply.writeNoException();
return true;
}
default:
{
return super.onTransact(code, data, reply, flags);
}
}
}
private static class Proxy implements com.sc.binder.test.ILoginInterface
{
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 login() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
boolean _status = mRemote.transact(Stub.TRANSACTION_login, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
getDefaultImpl().login();
return;
}
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
@Override public void loginCallback(boolean res, java.lang.String user) 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.writeInt(((res)?(1):(0)));
_data.writeString(user);
boolean _status = mRemote.transact(Stub.TRANSACTION_loginCallback, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
getDefaultImpl().loginCallback(res, user);
return;
}
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
public static com.sc.binder.test.ILoginInterface sDefaultImpl;
}
static final int TRANSACTION_login = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_loginCallback = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
public static boolean setDefaultImpl(com.sc.binder.test.ILoginInterface impl) {
if (Stub.Proxy.sDefaultImpl == null && impl != null) {
Stub.Proxy.sDefaultImpl = impl;
return true;
}
return false;
}
public static com.sc.binder.test.ILoginInterface getDefaultImpl() {
return Stub.Proxy.sDefaultImpl;
}
}
public void login() throws android.os.RemoteException;
public void loginCallback(boolean res, java.lang.String user) throws android.os.RemoteException;
}
aidl
interface ILoginInterface {
void login();
void loginCallback(boolean res,String user);
}
Server
public class MyService extends Service {
@Override
public IBinder onBind(Intent intent) {
return new ILoginInterface.Stub() {
@Override
public void login() throws RemoteException {
Log.d("binder >>> ", "serviceStartActivity");
serviceStartActivity();
}
@Override
public void loginCallback(boolean res, String user) throws RemoteException {
}
};
}
private void serviceStartActivity() {
Intent intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
}
Client
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
iLogin = ILoginInterface.Stub.asInterface(service);
Log.d("binder >>> ", "onServiceConnected");
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
public void startLogin(View view) {
if (iLogin != null) {
try {
iLogin.login();
} catch (RemoteException e) {
}
}
}
通讯过程
1、Client获取Server的代理接口BinderProxy(代理定义的方法与Server一一对应)
2、Client发送数据(copy_from_user)到BinderProxy(内核缓存区);
2、BinderProxy将数据打包成Parcel对象 ;
3、BinderProxy调用remote.transact(),将打包的Parcel对象发送给内核中的Binder驱动
4、Binder驱动找到真正的Binder对象,唤醒Server进程;
5、Server进程读取Binder请求数据,调用onTransact()(检验、解包),执行目标方法;(内核缓存区与Binder创建的接收缓存区存在映射关系,Server与Binder创建的接收缓存区存在映射关系)。
6、Server返回结果给Binder驱动;
7、Binder驱动返回结果给Client。