之前写过aidl在androidstudio中的使用的博客http://blog.youkuaiyun.com/u010800708/article/details/72983482,现在根据之前的例子,探索aidl的原理。
先用一张图
在android系统中不同的app拥有不同的进程,每个进程都在各自的内存区域。相互不同通信,这是linux底层决定的。不同的进程之间想要通信,就需要通过Binder。
Binder驱动位于系统的底层,有一块共享内存区域,不同的进程想要相互通信,就需要通过Binder驱动,被访问的进程也就是服务端会在Binder驱动这块共享内存中产生一个引用。
客户端进程会持有同样的引用到这块共享内存中找到这个引用。所有的通信都是在这块共享内存中完成的。
进程A想访问进程B,进程A中aidl文件中的proxy会将数据写到底层Binder驱动里面,然后让Binder驱动里面的c、c++去访问进程B中aidl文件的Stub里面的函数。
进程A中aidl文件中的proxy相当于客户端,进程B中aidl文件中的Stub相当于服务端。
当进程A与进程B已经建立连接了,服务端进程B想要返回数据给进程A,就需要进程B中aidl文件中的proxy去写数据到Binder驱动,由Binder驱动去回调进程A中aidl文件中的Stub
总之就是,利用Stub存根接收Binder底层调用,利用roxy去主动连接Binder引用
获取系统服务也是通过IPC
现在分析IConnect.aidl,Build->Make Project编译之后会生成IConnect.java文件位于目录
打开这个文件
package com.aidl.server;
public interface IConnect extends android.os.IInterface {
/**
* Local-side IPC implementation stub class.
*/
public static abstract class Stub extends android.os.Binder implements com.aidl.server.IConnect {
private static final java.lang.String DESCRIPTOR = "com.aidl.server.IConnect";
/**
* Construct the stub at attach it to the interface.
*/
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.aidl.server.IConnect interface,
* generating a proxy if needed.
*/
public static com.aidl.server.IConnect asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.aidl.server.IConnect))) {
return ((com.aidl.server.IConnect) iin);
}
return new com.aidl.server.IConnect.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_connect: {
data.enforceInterface(DESCRIPTOR);
java.lang.String _result = this.connect();
reply.writeNoException();
reply.writeString(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.aidl.server.IConnect {
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 java.lang.String connect() throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.lang.String _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_connect, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
static final int TRANSACTION_connect = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
public java.lang.String connect() throws android.os.RemoteException;
}
这个IConnect.java文件,可以包含两个部分,Stub(存根)、proxy
在IConnect.java文件中的
private static final java.lang.String DESCRIPTOR = “com.aidl.server.IConnect”;
这个DESCRIPTOR就是在Binder驱动中存入的aidl引用,是非常重要的
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
上面的方法的作用是在生成Binder对象的时候把Binder描述DESCRIPTOR和Binder对象绑定起来。
在asInterface(IBinder ibinder)方法中有一处,在本地通过DESCRIPTOR描述查找Binder对象。是考虑到是在同一进程访问,没有跨进程。
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
如果是跨进程就 new com.aidl.server.IConnect.Stub.Proxy(obj)
Proxy实际上实现了aidl接口,Proxy implements com.aidl.server.IConnect
public static com.aidl.server.IConnect asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.aidl.server.IConnect))) {
return ((com.aidl.server.IConnect) iin);
}
return new com.aidl.server.IConnect.Stub.Proxy(obj);
}
transact 通过native方法去连接IBinder驱动,根据描述去找到java层的进程B里面的aidl,然后去连接Stub,Stub会回调onTransact方法返回数据
transact告诉进程B要调用connect(),但是函数不能传递进来,所以给aidl接口中的所有方法赋了一个常量值,Binder驱动只要告诉进程B调用哪个常量对应的方法即可。
static final int TRANSACTION_connect = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
@Override
public java.lang.String connect() throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.lang.String _result;
try {
//把该aidl引用写入到Binder驱动中
_data.writeInterfaceToken(DESCRIPTOR);
//写入数据到Binder驱动,这行执行后,IBiner引用就会连接服务端
mRemote.transact(Stub.TRANSACTION_connect, _data, _reply, 0);
//读取异常
_reply.readException();
读取返回的数据,如果接口方法由返回值的话
_result = _reply.readString();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
执行mRemote.transact(Stub.TRANSACTION_connect, _data, _reply, 0);之后,binder驱动通过IBinder引用找到服务端进程aidl引用,调用服务端aidl对象中的方法,通过onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags)回调给客户端。
@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_connect: {
//验证DESCRIPTOR是否有错
data.enforceInterface(DESCRIPTOR);
//调用进程B返回的aidl对象的connect()方法
java.lang.String _result = this.connect();
reply.writeNoException();
//把返回值数据写到reply中
reply.writeString(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
什么时候把AIDL引用写入到Binder驱动的,在构造函数初始化的时候,也会执行父类Binder的构造函数,在父类的构造函数中执行写入。
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
public Binder(){
//native方法
init();
}
private native final void init();
本文深入探讨了Android中AIDL的工作原理,详细介绍了Binder机制如何支撑不同进程间通信,包括客户端和服务端的角色定义、Binder驱动的功能及交互流程,并分析了IConnect.aidl编译后的IConnect.java文件。
1104

被折叠的 条评论
为什么被折叠?



