Binder机制浅析
来源:互联网 发布:淘宝店怎么加入天猫 编辑:程序博客网 时间:2024/06/14 13:56
关于Binder机制,看了2天还是“糊里糊涂”的,该总结自己理解的Binder了。纯属自己总结,不对的地方,请多多指正。
Binder机制有啥用
Binder机制主要解决的是IPC(Inner Process Communicate),进程间通信问题。不同进程管理者自己的“东西”(内存),有属性,方法之类的,如果进程A想访问进程B的“东西”,只能通过IPC实现。
IPC的形式有很多种,如共享内存,管道,socket,文件等等,至于Android为什么还要自己设计一套专门的机制去实现IPC,主要考虑2方面:(1)性能(只拷贝一次)。(2)安全。
Binder机制的4个角色
(1)Client: 客户端,可以是任意一个进程,是远程(服务)请求的发起者。
(2)Server: 服务端,可以是任意一个进程,主要提供服务,请求的执行者。
(3)ServiceManager: Server需要在这里注册自己,提供自己的信息,Client可以在这里获取Server的引用。
(4)Binder驱动: Server和Client通信的媒介。
Binder机制实现IPC的流程
新建Server后,需要在ServiceManager注册,提供自己的信息。ServiceManager会根据Server的信息,生成IBinder引用,相当于Server的“引用“。
Client向ServiceManager查询目标Server,并获取目标Server的IBinder引用。有没有发现,Client向ServiceManager查询Server,也是一个IPC的过程,此时ServiceManager也是一个Server。由于ServiceManger的IBinder是固定的,而且别所有人知道的,所以Client还是很容易获取ServiceManager的IBinder,从而访问ServiceManager。ServiceManager会返回目标Server的IBinder对象,此时Client就可以与Server“通信“了。
Client发出请求,调用Server的方法,此时Client的线程会挂起,Binder驱动会把Client要传送的数据从Client的用户空间复制到Server内核空间的内存中,因为Server内核空间的内存已经通过mmap映射到Server的用户空间中,Binder驱动只需要将刚才复制之后的数据所在的内核空间的地址告诉Server就行,这样Server就可以获取Client传送过来的数据了。这就是传说中,一次拷贝。相反,待Server执行完请求的方法后,Binder驱动通过相同的方法,将Server的结果数据从Server的用户空间复制到Client的内核空间中,并将地址告诉Client即可。因为Client请求时,线程被挂起,现在结果已经有了,Binder驱动唤起Client线程,通知Client请求的方法已经执行完了,你可以继续干你的活了。
Binder机制的使用:AIDL(Android Interface Define Language)
我们从使用的代码进一步了解Binder机制。两个不同进程通信,需要统一“语言”,需要做一定的规范,要不然进程A怎么知道进程B有什么呢。所以就有了AIDL。
我们先创建一个有计算功能的Server,提供Client计算用。
创建一个Calculator.aidl,代码如下:
package com.johan.aidl;interface Calculator { int add(int num1, int num2); int sub(int num1, int num2);}
eclipse工具就会调用aidl.exe自动帮我们生成对应的名为Calculator的java文件(在gen目录下),代码如下:
package com.johan.aidl;public interface Calculator extends android.os.IInterface { /** Local-side IPC implementation stub class. */ public static abstract class Stub extends android.os.Binder implements com.johan.aidl.Calculator { private static final java.lang.String DESCRIPTOR = "com.johan.aidl.Calculator"; /** Construct the stub at attach it to the interface. */ public Stub() { this.attachInterface(this, DESCRIPTOR); } /** * Cast an IBinder object into an com.johan.aidl.Calculator interface, * generating a proxy if needed. */ public static com.johan.aidl.Calculator asInterface(android.os.IBinder obj) { if ((obj == null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin != null) && (iin instanceof com.johan.aidl.Calculator))) { return ((com.johan.aidl.Calculator) iin); } return new com.johan.aidl.Calculator.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_add: { data.enforceInterface(DESCRIPTOR); int _arg0; _arg0 = data.readInt(); int _arg1; _arg1 = data.readInt(); int _result = this.add(_arg0, _arg1); reply.writeNoException(); reply.writeInt(_result); return true; } case TRANSACTION_sub: { data.enforceInterface(DESCRIPTOR); int _arg0; _arg0 = data.readInt(); int _arg1; _arg1 = data.readInt(); int _result = this.sub(_arg0, _arg1); reply.writeNoException(); reply.writeInt(_result); return true; } } return super.onTransact(code, data, reply, flags); } private static class Proxy implements com.johan.aidl.Calculator { 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 int add(int num1, int num2) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); int _result; try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeInt(num1); _data.writeInt(num2); mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0); _reply.readException(); _result = _reply.readInt(); } finally { _reply.recycle(); _data.recycle(); } return _result; } @Override public int sub(int num1, int num2) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); int _result; try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeInt(num1); _data.writeInt(num2); mRemote.transact(Stub.TRANSACTION_sub, _data, _reply, 0); _reply.readException(); _result = _reply.readInt(); } finally { _reply.recycle(); _data.recycle(); } return _result; } } static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); static final int TRANSACTION_sub = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); } public int add(int num1, int num2) throws android.os.RemoteException; public int sub(int num1, int num2) throws android.os.RemoteException;}
我们开始解析eclipse帮我们生成的类。首先是这个类是一个继承IInterface 接口,don’t care。这个接口定义了两个内部类,Stub和Proxy。
我们先看看Stub(存根)这个类,这个类是一个抽象类,继承Binder,证明他就是一个Binder,我们写一个服务类时,继承Service,当客户端bindService时,返回的就是这个Binder的子类。还实现了我们定义的aidl接口,交给子类去实现。我们看他的构造函数:
private static final java.lang.String DESCRIPTOR = "com.johan.aidl.Calculator";public Stub() { this.attachInterface(this, DESCRIPTOR);}
构造函数里的attachInterface的作用是保存自己的描述和引用,下面会有用到,继续看看asInterface这个方法:
public static com.johan.aidl.Calculator asInterface(android.os.IBinder obj) { if ((obj == null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin != null) && (iin instanceof com.johan.aidl.Calculator))) { return ((com.johan.aidl.Calculator) iin); } return new com.johan.aidl.Calculator.Stub.Proxy(obj);}
obj.queryLocalInterface(DESCRIPTOR)根据描述查看本地是否有目标服务类,如果想调用的服务正好和自己在同一个进程,直接返回找到的服务类,如果没有找到,说明目标服务类和自己不在同一个进程,则返回Proxy代理类。这下我们得好好看看这个代理类,单独拿出来:
private static class Proxy implements com.johan.aidl.Calculator { 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 int add(int num1, int num2) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); int _result; try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeInt(num1); _data.writeInt(num2); mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0); _reply.readException(); _result = _reply.readInt(); } finally { _reply.recycle(); _data.recycle(); } return _result; } @Override public int sub(int num1, int num2) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); int _result; try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeInt(num1); _data.writeInt(num2); mRemote.transact(Stub.TRANSACTION_sub, _data, _reply, 0); _reply.readException(); _result = _reply.readInt(); } finally { _reply.recycle(); _data.recycle(); } return _result; }}
代理类持有服务类的IBinder引用,也实现了我们定义的aidl接口,所以他“算是”有服务类功能。一般客户端都会获取到的服务类,都是这个代理类。我们调用这个代理服务类的方法,如add方法,代码:
@Overridepublic int add(int num1, int num2) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); int _result; try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeInt(num1); _data.writeInt(num2); mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0); _reply.readException(); _result = _reply.readInt(); } finally { _reply.recycle(); _data.recycle(); } return _result;}
会先从池中取出两个Parcel对象存放传送的数据和返回的结果,然后调用IBinder的transact方法,此时,客户线程会挂起。通过Binder驱动,服务进程的Stub(真正的服务类)会调用onTransact方法。IBinder调用transact方法时,传入Stub.TRANSACTION_add值,这就指明要服务类调用add方法,参数通过_data传进去,服务类执行完目标方法后,会把结果写入_reply,此时,Binder驱动会唤醒客户线程,代理服务类通过读取_reply数据返回给客户。
static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);static final int TRANSACTION_sub = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
AIDL为我们接口每一个方法定义了一个标志,好让服务类知道客户请求的是哪个方法。AIDL算是分析完了,如果可以的话,建议结合例子会更加深入。
AIDL例子代码
- 浅析Android binder机制
- Android Binder机制浅析
- 浅析Android binder机制
- Android Binder机制浅析
- 浅析Android binder机制
- 图文浅析Binder机制
- Android Binder机制浅析
- Binder机制浅析
- Android Binder机制浅析
- Android Binder机制浅析
- Binder机制浅析
- Android Binder机制浅析
- Binder机制原理浅析
- Android的Binder机制浅析
- Android的Binder机制浅析
- Android的Binder机制浅析
- Android的Binder机制浅析
- binder机制底层驱动浅析
- <JVM调优>为什么内存过大?
- 一个前端攻城狮的全栈之路第四弹:jade模板引擎的简单介绍和使用
- E
- #POJ2709#Painter (贪心)
- Java.lang.Math.ceil()方法和java.lang.Math.floor()方法
- Binder机制浅析
- android studio 打开ddms
- CSS,font-family,好看常用的中文字体
- 图片上鼠标悬停即出现含提示内容的div层
- 《慕课网玩转算法面试》笔记及习题解答1
- 《剑指offer》数字在排序数组中出现的次数
- 关于Hallmeow
- linux中ftp提示--553 Could not create file (绝对有用)
- shell脚本