概述
本篇文章为Android进程间通信 深入浅出AIDL系列的第二篇,建议配合AIDL第一篇食用
3. AIDL原理
3.1 AIDL是怎么工作的?
我们编写了aidl文件之后,啥也没干就自动拥有了跨进程通信的能力.这一切得归功于Android Studio根据aidl文件生成的IPersonManager.java
文件(生成的这个文件通过双击Shift输入IPersonManager.java
即可找到),它里面已经帮我们封装好了跨进程通信这块的逻辑(最终是通过Binder来完成的),所以这个IPersonManager.java
文件最终会打包进apk里面,我们才得以方便地进行跨进程通信.
3.2 详细解读
先来简单看下IPersonManager.java
的大致结构,为了更方便阅读,我将IPersonManager.aidl
文件中多余的方法全部删除,只剩下List<Person> getPersonList();
和void addPersonIn(in Person person);
:
/*
* This file is auto-generated. DO NOT MODIFY.
*/
package com.xfhy.allinone.ipc.aidl;
public interface IPersonManager extends android.os.IInterface {
/**
* Default implementation for IPersonManager.
*/
public static class Default implements com.xfhy.allinone.ipc.aidl.IPersonManager {
@Override
public java.util.List<com.xfhy.allinone.ipc.aidl.Person> getPersonList() throws android.os.RemoteException {
return null;
}
@Override
public void addPersonIn(com.xfhy.allinone.ipc.aidl.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.xfhy.allinone.ipc.aidl.IPersonManager {
private static final java.lang.String DESCRIPTOR = "com.xfhy.allinone.ipc.aidl.IPersonManager";
/**
* Construct the stub at attach it to the interface.
*/
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.xfhy.allinone.ipc.aidl.IPersonManager interface,
* generating a proxy if needed.
*/
public static com.xfhy.allinone.ipc.aidl.IPersonManager asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.xfhy.allinone.ipc.aidl.IPersonManager))) {
return ((com.xfhy.allinone.ipc.aidl.IPersonManager) iin);
}
return new com.xfhy.allinone.ipc.aidl.IPersonManager.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_getPersonList: {
data.enforceInterface(descriptor);
java.util.List<com.xfhy.allinone.ipc.aidl.Person> _result = this.getPersonList();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
case TRANSACTION_addPersonIn: {
data.enforceInterface(descriptor);
com.xfhy.allinone.ipc.aidl.Person _arg0;
if ((0 != data.readInt())) {
_arg0 = com.xfhy.allinone.ipc.aidl.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.xfhy.allinone.ipc.aidl.IPersonManager {
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.util.List<com.xfhy.allinone.ipc.aidl.Person> getPersonList() throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<com.xfhy.allinone.ipc.aidl.Person> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
boolean _status = mRemote.transact(Stub.TRANSACTION_getPersonList, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
return getDefaultImpl().getPersonList();
}
_reply.readException();
_result = _reply.createTypedArrayList(com.xfhy.allinone.ipc.aidl.Person.CREATOR);
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override
public void addPersonIn(com.xfhy.allinone.ipc.aidl.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.xfhy.allinone.ipc.aidl.IPersonManager sDefaultImpl;
}
static final int TRANSACTION_getPersonList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_addPersonIn = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
public static boolean setDefaultImpl(com.xfhy.allinone.ipc.aidl.IPersonManager impl) {
// Only one user of this interface can use this function
// at a time. This is a heuristic to detect if two different
// users in the same process use this function.
if (Stub.Proxy.sDefaultImpl != null) {
throw new IllegalStateException("setDefaultImpl() called twice");
}
if (impl != null) {
Stub.Proxy.sDefaultImpl = impl;
return true;
}
return false;
}
public static com.xfhy.allinone.ipc.aidl.IPersonManager getDefaultImpl() {
return Stub.Proxy.sDefaultImpl;
}
}
public java.util.List<com.xfhy.allinone.ipc.aidl.Person> getPersonList() throws android.os.RemoteException;
public void addPersonIn(com.xfhy.allinone.ipc.aidl.Person person) throws android.os.RemoteException;
}
这块代码看起来很长.咱依次来看,首先IPersonManager是一个接口,然后它继承自IInterface接口.IInterface接口是Binder接口的基类,要通过Binder传输的接口都必须继承自IInterface.它里面的方法就是我们在aidl文件中声明的2个方法.然后用2个整型的id用于标识在transact过程中客户端所请求的是哪个方法.IPersonManager.Stub继承自Binder并实现了IPersonManager接口.当客户端与服务端都位于同一个进程时,方法调用不会走跨进程的transact过程,而当两者位于不同进程时,方法调用需要走transact过程,这个逻辑是由Stub的内部代理Proxy完成的.
Default类就只是IPersonManager的默认实现,可以不用在意.
下面来单独分析一下Stub类
IPersonManager.Stub
public static abstract class Stub extends android.os.Binder implements com.xfhy.allinone.ipc.aidl.IPersonManager {
private static final java.lang.String DESCRIPTOR = "com.xfhy.allinone.ipc.aidl.IPersonManager";
/**
* Construct the stub at attach it to the interface.
*/
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.xfhy.allinone.ipc.aidl.IPersonManager interface,
* generating a proxy if needed.
*/
public static com.xfhy.allinone.ipc.aidl.IPersonManager asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.xfhy.allinone.ipc.aidl.IPersonManager))) {
return ((com.xfhy.allinone.ipc.aidl.IPersonManager) iin);
}
return new com.xfhy.allinone.ipc.aidl.IPersonManager.Stub.Proxy(obj);
}
}
- DESCRIPTOR是Binder的唯一标识,一般用当前Binder的类名表示.
- attachInterface()是将Binder对象转成客户端需要的AIDL接口类型对象.如果需要跨进程,则还需要封装一个Stub.Proxy对象再返回;如果不需要跨进程,那么直接将Service端的Stub直接返回就行.
接着看Stub剩余的方法:
@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_getPersonList: {
data.enforceInterface(descriptor);
java.util.List<com.xfhy.allinone.ipc.aidl.Person> _result = this.getPersonList();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
case TRANSACTION_addPersonIn: {
data.enforceInterface(descriptor);
//从data中序列化一个Person出来,然后调用addPersonIn()去添加这个Person
com.xfhy.allinone.ipc.aidl.Person _arg0;
if ((0 != data.readInt())) {
_arg0 = com.xfhy.allinone.ipc.aidl.Person.CREATOR.createFromParcel(data);
} else {
_arg0 = null;
}
this.addPersonIn(_arg0);
reply.writeNoException();
return true;
}
default: {
return super.onTransact(code, data, reply, flags);
}
}
}
- asBinder()就是将当前的Binder对象返回
- onTransact()方法是运行在服务端的线程池中的.这里看起来就像是同一个进程里面的调用一样,但其实已经涉及到跨进程通信了.当客户端跨进程请求服务端时,远程请求会通过系统底层封装后交由此方法来处理.服务端通过code来确定客户端请求的目标方法是什么,然后从data中取出目标方法所需的参数,然后执行目标方法.当目标方法执行完毕之后,向reply中写入返回值.
IPersonManager.Stub.Proxy
private static class Proxy implements com.xfhy.allinone.ipc.aidl.IPersonManager {
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;
}
}
这里的mRemote是用于远程请求的Binder.如果需要跨进程,那么客户端就是通过这个Proxy代理来进行远程调用的.来看看调用方法具体是怎么实现的
static final int TRANSACTION_getPersonList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_addPersonIn = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
@Override
public java.util.List<com.xfhy.allinone.ipc.aidl.Person> getPersonList() throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<com.xfhy.allinone.ipc.aidl.Person> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
boolean _status = mRemote.transact(Stub.TRANSACTION_getPersonList, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
return getDefaultImpl().getPersonList();
}
_reply.readException();
_result = _reply.createTypedArrayList(com.xfhy.allinone.ipc.aidl.Person.CREATOR);
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override
public void addPersonIn(com.xfhy.allinone.ipc.aidl.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();
}
}
- 这2个方法都是运行在客户端的,当客户端调用此方法时: 首先创建该方法所需要的输入型Parcel对象
_data
,输出型Parcel对象_reply
和返回值(如果有).然后将客户端方法的入参写入_data
里面,通过序列化的方式.接着调用transact方法发起RPC远程调用,当前线程会被挂起,然后服务端的onTransact方法会被调用,直到RPC过程返回后,当前线程才能继续执行.然后将方法的返回值写入到_reply
中,也是通过序列化的方式,最后返回_reply
中的数据. - Parcel对象是用来进行客户端与服务端进行数据传输的,只能传输可序列化的数据
应用层面的原理基本就这些了,如果再往里层探究的话,就会涉及到Binder机制里面比较底层的东西了.这里暂时不做分析.
下面这张图刚好总结上面的流程(来自Android开发艺术探索):
因为上面的IPersonManager.java
文件是自动生成的,所以是很有规律的.即使我们不用AIDL也完全可以自定义Binder,从而实现跨进程通信.
资料
- 文中代码仓库
- Android 接口定义语言 (AIDL)
- Android中AIDL的工作原理
- 你真的理解AIDL中的in,out,inout么?
- Android 深入浅出AIDL(一)
- RemoteCallbackList
- Android:学习AIDL,这一篇文章就够了(下)
- Android开发艺术探索
最后
以上就是笨笨水壶为你收集整理的Android进程间通信 深入浅出AIDL(二)的全部内容,希望文章能够帮你解决Android进程间通信 深入浅出AIDL(二)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复