AIDL中的Proxy,Stub以及其关系

本文深入探讨了AIDL在Android跨进程通信中的作用,详细分析了ITest.java接口、Proxy与Stub之间的层次关系,解释了Proxy如何通过Binder调用远程的Stub方法,实现了Client与Server端的交互。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在上篇文章中,了解了ITest.java与Proxy,Stub三者的层次关系。

public interface ITest extends android.os.IInterface
{
	//Stub是一个Binder,也是一个ITest
	public static abstract class Stub extends android.os.Binder implements com.example.aidl.ITest
	{
		...
		//Proxy是一个ITest
		private static class Proxy implements com.example.aidl.ITest
			{
				...
			}
		...
	static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
	}
//aidl中定义的方法	
public int add(int a, int b) throws android.os.RemoteException;
}

Proxy调用add方法时,会调用Binder的transact方法,开始其跨进程的调用。

private static class Proxy implements com.example.aidl.ITest
{
private android.os.IBinder mRemote;

//Proxy必然会持有Binder实例
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 a, int b) 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(a);
_data.writeInt(b);

//跨进程调用开始
mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}

transact方法会传入Stub.TRANSACTION_add这个标识,在Stub中的onTransact中处理:

public static abstract class Stub extends android.os.Binder implements com.example.aidl.ITest
{
private static final java.lang.String DESCRIPTOR = "com.example.aidl.ITest";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
 * Cast an IBinder object into an com.example.aidl.ITest interface,
 * generating a proxy if needed.
 */
public static com.example.aidl.ITest asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.example.aidl.ITest))) {
return ((com.example.aidl.ITest)iin);
}
return new com.example.aidl.ITest.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;
}

//在这里处理add
case TRANSACTION_add:
{
data.enforceInterface(descriptor);
int _arg0;
_arg0 = data.readInt();
int _arg1;
_arg1 = data.readInt();

//注意,Stub中的add方法并没有实现
int _result = this.add(_arg0, _arg1);
reply.writeNoException();
reply.writeInt(_result);
return true;
}
default:
{
return super.onTransact(code, data, reply, flags);
}
}
}
...
static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}

AIDL到底是用来干什么的呢?在这个例子中,定义了ITest.aidl后,生成了一个接口ITest.java,其中包含有Proxy和Stub,Proxy中的add方法,通过binder调用其他进程实现,也就是调用Stub中的add方法来实现。
所以,在Client端,只要能持有Proxy的引用,而Server端只要实现Stub接口,这样,Client便可调用Server中的方法了,前提是这些方法都在接口(ITest.aidl)中注册过。

<think>我们正在讨论IPC机制中的ProxyStub概念。根据引用[2]和[3],Proxy-Stub设计模式在IPC中用于包装底层的通信接口(如IBinder),使得应用程序不必直接与复杂的通信接口打交道,从而降低了开发的复杂性。 引用[2]提到,框架开发者(如Android系统框架)会提供AIDL工具,生成ProxyStub类,这样应用开发者就不需要自己实现这些类。引用[3]则详细说明了ProxyStub的作用: - Proxy类:运行在客户端进程,它将客户端的方法调用转换为跨进程调用(IPC)请求,并发送给服务端。它隐藏了底层的通信细节,给客户端提供了一个简单易用的接口(IA接口)。 - Stub类:运行在服务端进程,它接收来自客户端的IPC请求,并将这些请求转换为对服务端实际对象的方法调用。Stub类通常继承自Binder类,并实现了IA接口,但具体的业务逻辑由开发者实现(通过实现Stub中的抽象方法)。 所以,ProxyStub是IPC通信过程中的两个代理对象,它们分别位于客户端和服务端,共同完成跨进程调用的封装和转换。 现在,我们根据用户的问题,详细解释ProxyStub的定义与作用: ### 一、ProxyStub 的定义 1. **Proxy(代理)** - 位于**客户端进程**,实现服务端提供的接口(如IA接口)。 - 负责将客户端的方法调用**封装成跨进程请求**(包括参数打包),并通过Binder驱动发送到服务端。 - 接收服务端返回的结果,并解包返回给客户端。 2. **Stub(存根)** - 位于**服务端进程**,通常继承自 `Binder` 类并实现服务端接口(如IA接口)。 - 负责**接收并解析**来自客户端的请求(通过重写 `onTransact()` 方法)。 - 将解析后的请求**分派**给服务端实际的对象(即真正实现业务逻辑的对象)处理。 - 将处理结果打包返回给客户端。 ### 二、ProxyStub 的作用 1. **封装通信细节** - ProxyStub 隐藏了底层 IPC 的复杂操作(如数据序列化、Binder驱动调用等),让开发者只需关注业务逻辑。 - 例如:客户端调用 `proxy.add(1, 2)` 就像调用本地方法一样简单,无需关心跨进程通信过程[^3]。 2. **接口一致性** - Proxy 实现了与服务端相同的接口(IA接口),保证客户端调用方式与本地调用一致。 - Stub 在服务端将跨进程请求转换为对服务对象的方法调用,保证服务端处理逻辑与本地服务一致。 3. **数据序列化与反序列化** - Proxy 将方法参数打包(序列化)成 `Parcel` 对象,通过 Binder 驱动传输。 - Stub 从 `Parcel` 中解析(反序列化)参数,传递给服务对象,并将返回结果序列化后回传[^5]。 ### 三、工作流程示例 以客户端调用服务端的 `add(int a, int b)` 方法为例: ```mermaid sequenceDiagram participant Client participant Proxy participant BinderDriver participant Stub participant Service Client ->> Proxy: 调用 add(1, 2) Proxy ->> Proxy: 将参数打包为Parcel Proxy ->> BinderDriver: 发送请求 BinderDriver ->> Stub: 跨进程传递请求 Stub ->> Stub: 解包Parcel,解析参数 Stub ->> Service: 调用实际对象的add(1,2) Service ->> Stub: 返回结果3 Stub ->> Stub: 将结果打包为Parcel Stub ->> BinderDriver: 返回结果 BinderDriver ->> Proxy: 跨进程传递结果 Proxy ->> Proxy: 解包Parcel,得到结果3 Proxy ->> Client: 返回3 ``` ### 四、在 Android 中的具体实现(AIDL 工具) Android 通过 AIDL(Android Interface Definition Language)自动生成 ProxyStub 类: 1. **定义 AIDL 接口**(如 `IMathService.aidl`): ```aidl interface IMathService { int add(int a, int b); } ``` 2. **编译生成**: - 生成 `IMathService.Stub` 类(供服务端继承)。 - 生成 `IMathService.Stub.Proxy` 类(供客户端使用)。 3. **服务端实现**: ```java public class MathService extends IMathService.Stub { @Override public int add(int a, int b) { return a + b; } } ``` 4. **客户端绑定服务**: ```java IMathService proxy = IMathService.Stub.asInterface(binder); int result = proxy.add(1, 2); // 通过Proxy调用 ``` ### 五、设计模式优势 1. **解耦**:客户端和服务端通过接口(IA)通信,无需依赖具体实现[^2]。 2. **简化开发**:开发者只需关注业务逻辑,无需处理 IPC 底层细节。 3. **可扩展性**:接口变更时,只需更新 AIDL 定义并重新生成代码。 --- ### 总结 - **Proxy**:客户端代理,负责将本地调用转化为跨进程请求。 - **Stub**:服务端存根,负责将跨进程请求转化为本地调用。 - **核心价值**:通过封装 IPC 通信细节,提供与本地调用一致的编程体验,降低跨进程开发复杂度[^3][^5]。 §§相关问题§§ 1. AIDL 自动生成的 ProxyStub 类具体包含哪些方法? 2. 在非 Android 系统中,Proxy-Stub 模式如何实现? 3. 如何手动实现 ProxyStub 而不依赖 AIDL? 4. Parcel 序列化与反序列化的原理是什么?</think>### IPC 机制中的 StubProxy 定义与作用 在 IPC 机制中,**Stub** 和 **Proxy** 是 Proxy-Stub 设计模式的核心组件,用于**封装底层通信细节**,使开发者无需直接操作复杂的 IPC 接口(如 Binder 的 `IBinder`)。它们通过抽象层简化跨进程调用,工作原理如下: #### 一、核心定义 1. **Proxy(代理)** - **位置**:客户端进程 - **作用**: - 将客户端的本地方法调用**封装为跨进程请求** - 通过 Binder 驱动向服务端发送请求 - 接收服务端返回结果并解包给客户端 - **本质**:服务端接口的**本地代理对象**,对客户端表现为本地服务[^3][^5]。 2. **Stub(存根)** - **位置**:服务端进程 - **作用**: - 接收来自客户端的跨进程请求 - 解析请求参数并**调用服务端实际业务方法** - 将执行结果打包返回给客户端 - **本质**:服务端实现的**基础骨架**,屏蔽 Binder 底层细节[^3][^5]。 ```mermaid graph LR A[客户端] -->|调用 add(1,2)| B[Proxy] B -->|打包参数/发送请求| C[Binder Driver] C -->|转发请求| D[Stub] D -->|解包参数/调用真实方法| E[服务实现] E -->|返回结果 3| D D -->|打包结果| C C -->|返回结果| B B -->|解包结果| A ``` #### 二、核心作用 1. **通信封装** - Proxy 将方法调用转换为 `transact()` 操作(序列化参数) - Stub 通过 `onTransact()` 解析请求并分发给业务方法[^3][^5] - 示例:客户端调用 `proxy.add(1,2)` 实际触发 Binder 驱动的跨进程通信 2. **接口一致性** - ProxyStub **实现相同的接口**(如 `IMathService`) - 客户端调用 Proxy 的方法 = 直接调用服务端 Stub 的方法 - 开发者无需关注跨进程细节,像调用本地方法一样使用[^2][^3] 3. **线程管理** - Stub 在服务端**自动分配 Binder 线程**处理请求 - 当请求到达时,Binder 驱动从线程池取出线程执行 `onTransact()`[^5] - 避免阻塞服务端主线程 #### 三、在 Android 中的实现(AIDL 工具) Android 通过 AIDL(Android Interface Definition Language)自动生成 ProxyStub: ```java // 自动生成的 AIDL 代码片段 interface IMathService { int add(int a, int b); } class Proxy implements IMathService { @Override public int add(int a, int b) { // 1. 打包参数到 Parcel // 2. 通过 Binder 发送请求 // 3. 等待并解包结果 } } abstract class Stub extends Binder implements IMathService { @Override protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) { // 1. 解析 code 确定方法(如 add) // 2. 从 data 解包参数 // 3. 调用实际服务实现 // 4. 将结果写入 reply } } ``` #### 四、设计模式优势 1. **解耦** - 客户端依赖 Proxy 而非具体 IPC 实现 - 服务端通过 Stub 隔离 Binder 复杂性[^2][^3] 2. **开发效率** - AIDL 自动生成模板代码,减少手动错误 - 开发者只需关注业务逻辑实现(如 `add()` 的具体算法) 3. **安全与稳定** - ProxyStub 处理参数序列化/反序列化 - 防止客户端直接访问敏感 IPC 接口[^3] --- ### 总结 - **Proxy**:客户端的服务代理,**封装请求发送与结果解析** - **Stub**:服务端的请求处理器,**实现跨进程调用到本地方法的转换** - **核心价值**:通过抽象层隐藏 IPC 复杂性,提供透明的本地调用体验[^2][^3][^5]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值