Binder 机制AIDL 分析 ( AIDL 通信完整流程梳理 )
Posted 韩曙亮
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Binder 机制AIDL 分析 ( AIDL 通信完整流程梳理 )相关的知识,希望对你有一定的参考价值。
文章目录
AIDL 跨进程通信完整流程梳理
1、AIDL 文件编译
AIDL 文件 IMyAidlInterface.aidl 在客户端和服务端都有 , 编译时 , 都会在 " build\\generated\\aidl_source_output_dir\\debug\\out\\kim\\hsl\\aidl_demo " 目录生成 IMyAidlInterface.java 源文件 ;
这样在客户端与服务器端都可以调用 IMyAidlInterface.Stub 类的相关方法 , 主要是 asInterface 方法 , 用于获取远程服务或代理 ;
2、注册服务
在应用中 , 通过绑定 Service
注册服务 ;
// 通过 Action 和 包名 , 绑定远程服务
Intent intent = new Intent("android.intent.action.MyService");
intent.setPackage("kim.hsl.aidl_demo");
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
3、IMyAidlInterface.Stub.asInterface 方法获取远程服务
开启一个 ServiceConnection
, 在 ServiceConnection
的 onServiceConnected
方法中 ,
调用 IMyAidlInterface.Stub.asInterface
方法 ,
在 IMyAidlInterface.Stub.asInterface
方法中 , 传入我们需要的 Service
远程服务 ; 这里涉及到跨进程调用 , 拿到的是一个代理 ;
Stub 中定义了 asInterface
方法 , 该方法的作用是将 android.os.IBinder
对象转为 AIDL 接口对象 ; 传入的 DESCRIPTOR 描述符 , 用于描述用户想要哪个 Binder , android.os.IBinder 对象调用 queryLocalInterface 方法 , 检查本地服务是否存在 ;
- 如果可以找到本地服务对应的接口 , 可以直接返回本地服务 ;
- 如果没有找到本地服务 , 就会返回一个 Stub 代理 ;
详细的过程参考下面的代码 :
/**
* 将IBinder对象强制转换为kim.hsl.aidl_demo.IMyAidlInterface接口,必要时生成代理。
*/
public static kim.hsl.aidl_demo.IMyAidlInterface asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
// 传入 DESCRIPTOR 描述符 , 用于描述用户想要哪个 Binder
// android.os.IBinder 对象调用 queryLocalInterface 方法 , 检查本地服务
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
// 如果可以找到本地服务对应的接口 , 可以直接返回本地服务
if (((iin!=null)&&(iin instanceof kim.hsl.aidl_demo.IMyAidlInterface))) {
return ((kim.hsl.aidl_demo.IMyAidlInterface)iin);
}
// 如果没有找到本地服务 , 就会返回一个 Stub 代理
return new kim.hsl.aidl_demo.IMyAidlInterface.Stub.Proxy(obj);
}
4、IMyAidlInterface.Stub.Proxy 代理类
上述 IMyAidlInterface.Stub.asInterface
方法 , 最终返回一个代理 , 代理如下 :
在 IMyAidlInterface.java 中的代理中 , 实现了 3 3 3 个 AIDL 接口方法 ;
private static class Proxy implements kim.hsl.aidl_demo.IMyAidlInterface
{
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;
}
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
@Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException
{
}
/**
* in 写入, out 输出, inout 写入和输出
*/
@Override public void addStudent(kim.hsl.aidl_demo.Student student) throws android.os.RemoteException
{
}
/**
* 获取 Student 集合
*/
@Override public java.util.List<kim.hsl.aidl_demo.Student> getStudents() throws android.os.RemoteException
{
return _result;
}
}
5、IMyAidlInterface.Stub.Proxy 代理类方法执行
在主应用中 , 调用 IMyAidlInterface aidl
也就是 IMyAidlInterface.Stub.asInterface
方法返回的代理对象的 addStudent
方法 , 分析代理中的该方法 , 首先生成输入和输出数据 , 传参和反参都会传入 mRemote.transact
方法中 , 这是 Binder 的方法 ;
/**
* in 写入, out 输出, inout 写入和输出
*/
@Override public void addStudent(kim.hsl.aidl_demo.Student student) throws android.os.RemoteException
{
// 通过 Parcel 池获得两个对象 , 分别用于输入和输出
// 输入对象
android.os.Parcel _data = android.os.Parcel.obtain();
// 输出对象
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((student!=null)) {
_data.writeInt(1);
student.writeToParcel(_data, 0);
}
else {
_data.writeInt(0);
}
// 调用 Binder 的 transact 方法
boolean _status = mRemote.transact(Stub.TRANSACTION_addStudent, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
getDefaultImpl().addStudent(student);
return;
}
_reply.readException();
if ((0!=_reply.readInt())) {
student.readFromParcel(_reply);
}
}
finally {
_reply.recycle();
_data.recycle();
}
}
6、Binder.transact 方法执行
Binder 中的 transact
方法执行后 , 会回调 IMyAidlInterface.java 中的 Stub
内部类的 onTransact
方法 ,
Binder 的 transact 方法 ; 进入该方法后 , 会将原来的线程挂起 , 直到返回 , 原来的线程才会继续执行 , 这里非常容易出现 ANR ;
/**
* 远程对象的基类,由{@link IBinder}定义的轻量级远程过程调用机制的核心部分。
* 此类是IBinder的一个实现,它提供了此类对象的标准本地实现。
*
* <p>大多数开发人员不会直接实现这个类,
* 而是使用<a href=“{@docRoot}guide/components/aidl.html”>aidl</a>工具来描述所需的接口,
* 让它生成适当的Binder子类。
* 然而,您可以直接从Binder派生来实现您自己的定制RPC协议,
* 或者直接实例化一个原始Binder对象,将其用作可以跨进程共享的令牌。
*
* <p>这个类只是一个基本的IPC原语;
* 它对应用程序的生命周期没有影响,并且只有创建它的进程继续运行时才有效。
* 要正确使用此功能,您必须在顶级应用程序组件(a{@link android.app.Service}、
* {@link android.app.Activity}或{@link android.content.ContentProvider})
* 的上下文中执行此操作,该组件应保持运行。</p>
*
* <p>您必须记住流程可能会消失的情况,因此需要稍后重新创建新的活页夹,
* 并在流程再次启动时重新附加它。
* 例如,如果您在{@link android.app.Activity}中使用此函数,
* 则您的活动的进程可能会在活动未启动时被终止;
* 如果以后重新创建活动,则需要创建新的活页夹,
* 并再次将其交回正确的位置;
* 您需要注意的是,您的流程可能由于其他原因(例如接收广播)而启动,
* 这将不涉及重新创建活动,因此运行其代码以创建新的绑定。</p>
*
* @see IBinder
*/
public class Binder implements IBinder {
/**
* 默认实现回放地块并调用onTransact。在远程端,transact调用绑定器来执行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;
}
}
7、IMyAidlInterface.Stub.onTransact 方法执行
在 IMyAidlInterface.Stub.onTransact
方法中 , 通过方法对应的 ID 常量值匹配方法 , 在该方法中就会调用 IMyAidlInterface.Stub
中没有实现的抽象方法 ;
@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_basicTypes:
{
return true;
}
case TRANSACTION_addStudent:
{
return true;
}
case TRANSACTION_getStudents:
{
return true;
}
default:
{
return super.onTransact(code, data, reply, flags);
}
}
}
8、调用 Service 中实现的 IMyAidlInterface.Stub 抽象方法
IMyAidlInterface.Stub
中的抽象方法 , 在 Service 中实现 ;
/**
* 创建 IMyAidlInterface.Stub 抽象类子类对象 , 实现其中的 3 个抽象方法
* Binder 调用 transact 方法时 , 会调用 IMyAidlInterface.Stub 的 onTransact 方法
* 在 IMyAidlInterface.Stub.onTransact 方法中会调用下面实现的抽象方法
*/
private IMyAidlInterface.Stub stub = new IMyAidlInterface.Stub() {
@Override
public void basicTypes(int anInt, long aLong,
boolean aBoolean, float aFloat, double aDouble,
String aString) throws RemoteException {
Log.i(TAG, "anInt=" + anInt + " , aLong=" + aLong +
" , aBoolean=" + aBoolean + " , aFloat=" + aFloat +
" , aDouble=" + aDouble + " , aString=" + aString);
}
@Override
public void addStudent(Student student) throws RemoteException {
if (students != null) {
students.add(student);
}
}
@Override
public List<Student> getStudents() throws RemoteException {
return students;
}
};
以上是关于Binder 机制AIDL 分析 ( AIDL 通信完整流程梳理 )的主要内容,如果未能解决你的问题,请参考以下文章
Binder 机制AIDL 分析 ( 创建 AIDL 文件 | 创建 Parcelable 类 | AIDL 中使用 Parcelable 类 | 编译工程生成 AIDL 对应的Java源文件 )(代