内容简介:Binder机制在Android系统中地位毋庸置疑,system_server就通过Binder来实现进程间的通信,从而达到管理、调用一系列系统服务的能力。本文就AIDL来解读一下Binder机制的。 先了解一下如下几个概念:还有一点需要说明一下:当一个Service向AMS进行注册时,传递的过去的以及保存在AMS中的是一个Binder对象。当Client需要跟Service进行通信,通过AMS查询到其实是一个BinderProxy,因为可以有多个Client同时跟Service进行通信。当然如果Servi
Binder机制在Android系统中地位毋庸置疑,system_server就通过Binder来实现进程间的通信,从而达到管理、调用一系列系统服务的能力。本文就AIDL来解读一下Binder机制的。 先了解一下如下几个概念:
IBinder 、 Binder 、 BinderProxy 、 IInterface
- IBinder : 根据官方的说明文档IBinder定义的是一种使对象具备远程通信能力的接口,他的子类是Binder。IBinder内部预先定义了一些IPC需要用到的接口,实现IBinder的对象可以被Binder Drivder在IPC过程中传递;
- Binder : 实现了IBinder,具备IPC通信的能力。在IPC通信过程中,Binder代表的是Server的本地对象;
- BinderProxy : BinderProxy是Binder的内部类,同样实现了IBinder,不同于Binder的是,BinderProxy是Binder对象在Client端的一个代理,用以提供Server具备的接口;
- IInterface : 代表的是Server所具备的接口;
还有一点需要说明一下:当一个Service向AMS进行注册时,传递的过去的以及保存在AMS中的是一个Binder对象。当Client需要跟Service进行通信,通过AMS查询到其实是一个BinderProxy,因为可以有多个Client同时跟Service进行通信。当然如果Service和Client在同一进程,AMS返回的还是一个Binder对象,毕竟没有必要进行IPC。 在进行IPC时,Binder Drivder会在中间帮忙转换Binder和BinderProxy。
AIDL
还是按照 Android Service详解(二) 的例子来解释
现在我们来看一下系统自动生成的aidl文件具体有些什么:
/*
* This file is auto-generated. DO NOT MODIFY.
* Original file: /Users/lebens/Development/WorkSpace/jxx_workspace/Server/app/src/main/aidl/jxx/com/server/aidl/IServerServiceInfo.aidl
*/
package jxx.com.server.aidl;
public interface IServerServiceInfo extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements jxx.com.server.aidl.IServerServiceInfo
{
private static final java.lang.String DESCRIPTOR = "jxx.com.server.aidl.IServerServiceInfo";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an jxx.com.server.aidl.IServerServiceInfo interface,
* generating a proxy if needed.
*/
public static jxx.com.server.aidl.IServerServiceInfo asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof jxx.com.server.aidl.IServerServiceInfo))) {
return ((jxx.com.server.aidl.IServerServiceInfo)iin);
}
return new jxx.com.server.aidl.IServerServiceInfo.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_getServerInfo:
{
data.enforceInterface(descriptor);
jxx.com.server.aidl.ServerInfo _result = this.getServerInfo();
reply.writeNoException();
if ((_result!=null)) {
reply.writeInt(1);
_result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
}
else {
reply.writeInt(0);
}
return true;
}
case TRANSACTION_setServerInfo:
{
data.enforceInterface(descriptor);
jxx.com.server.aidl.ServerInfo _arg0;
if ((0!=data.readInt())) {
_arg0 = jxx.com.server.aidl.ServerInfo.CREATOR.createFromParcel(data);
}
else {
_arg0 = null;
}
this.setServerInfo(_arg0);
reply.writeNoException();
if ((_arg0!=null)) {
reply.writeInt(1);
_arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
}
else {
reply.writeInt(0);
}
return true;
}
default:
{
return super.onTransact(code, data, reply, flags);
}
}
}
private static class Proxy implements jxx.com.server.aidl.IServerServiceInfo
{
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 jxx.com.server.aidl.ServerInfo getServerInfo() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
jxx.com.server.aidl.ServerInfo _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getServerInfo, _data, _reply, 0);
_reply.readException();
if ((0!=_reply.readInt())) {
_result = jxx.com.server.aidl.ServerInfo.CREATOR.createFromParcel(_reply);
}
else {
_result = null;
}
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override public void setServerInfo(jxx.com.server.aidl.ServerInfo serverinfo) 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 ((serverinfo!=null)) {
_data.writeInt(1);
serverinfo.writeToParcel(_data, 0);
}
else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_setServerInfo, _data, _reply, 0);
_reply.readException();
if ((0!=_reply.readInt())) {
serverinfo.readFromParcel(_reply);
}
}
finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_getServerInfo = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_setServerInfo = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
}
public jxx.com.server.aidl.ServerInfo getServerInfo() throws android.os.RemoteException;
public void setServerInfo(jxx.com.server.aidl.ServerInfo serverinfo) throws android.os.RemoteException;
}
复制代码
- 这个文件中,我们看到IServerServiceInfo实现了IInterface,说明IServerServiceInfo具备了IPC通信需要的接口,最底下我们也可以看到定义的getServerInfo()、setServerInfo()两个方法;
- 接着来看Stub这个对象,它是IServerServiceInfo的静态内部类,继承了Binder同时实现了IServerServiceInfo。这意味着Stub可以通过Binder Driver进行进程间传递,同时又具备了IPC所需要的接口,实际我们在Service中asBinder()返回的就是这个对象;
- Proxy对象,这又是一个代理对象,不过代理的是BinderProxy。这个对象存在的意思就是代理BinderProxy,将Client的操作转化成BinderProxy去跟Server通信。
- Proxy 和 Stub 的区别在于,Stud本身就是一个Binder对象,可以直接被Binder Driver传递,而Proxy只是代表Service提供的IPC接口,实际使用内部的被代理的mRemote来实现IPC。
Stub
关于Stub再来看几点:
- DESCRIPTOR : 这是用来唯一表示Stub的,当Stub被实例化时会通过DESCRIPTOR来保存owner对象,也就是Stub所代表的IInterface,同时在queryLocalInterface如果是在同一进程查询的话就是返回的Stub;
- TRANSACTION_getServerInfo 、 TRANSACTION_setServerInfo : 这两个用来标识Client操作的接口方法。
- asInterface : 这个方法就是将Binder,转换成Client需要的接口对象,如果Binder Driver返回的是一个BinderProxy对象,则创建一个Proxy返回给Client。
- onTransact : 这个方法跟下面的Proxy对象一同分析。
Proxy
- mRemote : 这是一个BinderProxy对象,由Binder Driver传递而来。Proxy的IPC都是通过mRemote来实现的;
- 这里我们还看到的了我们定义的接口方法,这些方法都是提供给Client使用的,用于跟Server通信;
- mRemote的transact() : 在Binder Driver的帮助下,最终会调用到Stub的onTransact()中。
onTransact()
以getServerInfo()为例来分析一下onTransact传递过程。 首先我们在Proxy的实现是这样的
@Override public jxx.com.server.aidl.ServerInfo getServerInfo() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
jxx.com.server.aidl.ServerInfo _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(IServerServiceInfo.Stub.TRANSACTION_getServerInfo, _data, _reply, 0);
_reply.readException();
if ((0!=_reply.readInt())) {
_result = jxx.com.server.aidl.ServerInfo.CREATOR.createFromParcel(_reply);
}
else {
_result = null;
}
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
复制代码
- _data 、 _reply 分别用于Client向Server传递参数和Server向Client返回结果,这2个内的参数都是要序列化的,毕竟IPC;
- 通过mRemote.transact开始调用Server的方法;
- 通过_reply读取Server返回的数据,并反序列化结果,将之返回;
从上面的分析可以知道,这里的mRemote其实是一个BinderProxy对象,我们去看一下这个方法
/**
* Default implementation rewinds the parcels and calls onTransact. On
* the remote side, transact calls into the binder to do the IPC.
*/
public final boolean transact(int code, @NonNull Parcel data, @Nullable Parcel reply,
int flags) throws RemoteException {
if (false) Log.v("Binder", "Transact: " + code + " to " + this);
if (data != null) {
data.setDataPosition(0);
}
boolean r = onTransact(code, data, reply, flags);
if (reply != null) {
reply.setDataPosition(0);
}
return r;
}
复制代码
最终调用的是Binder内的onTransact(),也就是Stub的onTransact(),我们来看一下
@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_getServerInfo:
{
data.enforceInterface(descriptor);
jxx.com.server.aidl.ServerInfo _result = this.getServerInfo();
reply.writeNoException();
if ((_result!=null)) {
reply.writeInt(1);
_result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
}
else {
reply.writeInt(0);
}
return true;
}
case TRANSACTION_setServerInfo:
{
data.enforceInterface(descriptor);
jxx.com.server.aidl.ServerInfo _arg0;
if ((0!=data.readInt())) {
_arg0 = jxx.com.server.aidl.ServerInfo.CREATOR.createFromParcel(data);
}
else {
_arg0 = null;
}
this.setServerInfo(_arg0);
reply.writeNoException();
if ((_arg0!=null)) {
reply.writeInt(1);
_arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
}
else {
reply.writeInt(0);
}
return true;
}
default:
{
return super.onTransact(code, data, reply, flags);
}
}
复制代码
在内部可以看到case TRANSACTION_getServerInfo 下的操作其实也是很简单,就是把Client需要的结果通过reply传递回Client
总结
通过上面的代码分析,AIDL我们可以快速实现IPC,我们来总结一下:
- Server需要定义提供给Client的接口,也即实现IInterface,同时还要提供一个Binder用来供Binder Driver找到Server,通过DESCRIPTOR确定;
- Client在跟Server通信之前需要获得一个Binder或者BinderProxy对象,通过Binder Driver跟Server建立联系;
- Binder Driver在通信过程中自动转换了BinderProxy 和 Binder;
通过这个例子的分析,其实系统的AMS管理各种系统服务也是同样的套路,通过2个Binder建立通信。
还有一点需要注意: Binder或者BinderProxy都是运行在他们自己的Binder池中的,也就是直接通过Binder通信的话,需要注意线程切换
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 快速失败机制 & 失败安全机制
- JavaScript线程机制与事件机制
- 区块链是怎样将分布式组网机制、合约机制、共识机制等技术结合并应用
- Java内存机制和GC回收机制-----笔记
- javascript垃圾回收机制 - 标记清除法/引用计数/V8机制
- Android 8.1 源码_机制篇 -- 全面解析 Handler 机制(原理篇)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Machine Learning
Kevin Murphy / The MIT Press / 2012-9-18 / USD 90.00
Today's Web-enabled deluge of electronic data calls for automated methods of data analysis. Machine learning provides these, developing methods that can automatically detect patterns in data and then ......一起来看看 《Machine Learning》 这本书的介绍吧!