【Android】AIDL之一个简单的demo
AIDL 的一个简单例子
在 Android 系统中,服务通常通过 Binder 机制注册到系统,并使用 RPC(远程过程调用) 处理客户端请求。以下是一个完整的示例,展示如何实现一个简单的 Binder 服务,并演示客户端如何通过 RPC 调用服务端方法。
1. 定义服务接口(AIDL)
首先,使用 Android 的 AIDL(Android Interface Definition Language) 定义服务接口。
文件:IAGM.aidl
// IAGM.aidl package com.example.agm; interface IAGM { int performCalculation(int a, int b); String getVersion(); }
2. 实现服务端(Server)
服务端实现 IAGM 接口,并通过 Binder 注册到系统。
文件:AGM.java
// AGM.java package com.example.agm; import android.os.Binder; import android.os.IBinder; import android.os.IInterface; import android.os.RemoteException; public class AGM extends Binder implements IAGM { @Override public int performCalculation(int a, int b) throws RemoteException { return a + b; // 示例:返回两数之和 } @Override public String getVersion() throws RemoteException { return "1.0"; // 示例:返回版本号 } // 注册为系统服务(通常在 SystemServer 中调用) public static void registerService() { android.os.ServiceManager.addService("agm_service", new AGM()); } }
3. 客户端调用(Client)
客户端通过 Binder 获取服务代理,并调用远程方法。
文件:ClientActivity.java
// ClientActivity.java package com.example.agmclient; import android.os.Bundle; import android.os.IBinder; import android.os.IInterface; import android.os.Parcel; import android.os.RemoteException; import androidx.appcompat.app.AppCompatActivity; import com.example.agm.IAGM; public class ClientActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 通过 Binder 获取服务代理 IAGM agmService = IAGM.Stub.asInterface( android.os.ServiceManager.getService("agm_service") ); try { // 调用远程方法 int result = agmService.performCalculation(10, 20); String version = agmService.getVersion(); // 打印结果 System.out.println("Calculation result: " + result); // 输出 30 System.out.println("Service version: " + version); // 输出 "1.0" } catch (RemoteException e) { e.printStackTrace(); } } }
4. 服务注册到系统
在 Android 系统启动时(如 SystemServer 中),注册服务:
// 在 SystemServer.java 中添加 AGM.registerService();
5. RPC 处理流程
服务端启动:AGM 服务通过 ServiceManager.addService() 注册到 Binder。
客户端获取代理:客户端通过 ServiceManager.getService() 获取 IAGM 的代理对象。
远程调用:
客户端调用 agmService.performCalculation(10, 20)。
Binder 驱动将请求转发到服务端线程池。
服务端执行 performCalculation() 并返回结果。
客户端通过 onTransact()(自动生成)接收结果。
关键点说明
AIDL 生成代码:编译后,AIDL 工具会自动生成 IAGM.Stub 和 IAGM.Stub.Proxy 类,处理 RPC 通信。
线程池:服务端默认使用 Binder 线程池处理并发请求。
安全性:需处理权限检查(如 checkCallingPermission())。
完整调用栈
Client (UI Thread) → Binder Proxy → Binder Driver → Service Thread Pool → AGM.performCalculation()
通过这种方式,Android 的 Binder 机制实现了跨进程的 RPC 调用。
JoinRpcThreadpool() 的作用
在 Android 的 Binder 机制中,当调用 joinRpcThreadpool() 时,主线程的行为会发生以下变化:
1. joinRpcThreadpool() 的作用
功能:joinRpcThreadpool() 是 Android Binder 线程池的一个方法,用于阻塞当前线程,直到线程池中的所有任务完成或线程池被销毁。
设计目的:在服务端代码中,通常希望主线程(或初始化线程)不直接退出,而是持续监听和处理来自客户端的 RPC 请求。
2. 主线程的行为变化
阻塞主线程:调用 joinRpcThreadpool() 后,主线程会进入阻塞状态,不再执行后续代码。
调度者角色:主线程不再继续执行原来的逻辑(如返回 main 函数),而是成为 RPC 请求的调度者:
Binder 驱动会将客户端的 RPC 请求分发给线程池中的工作线程。
主线程本身不处理请求,但会等待线程池中的任务完成(或线程池被销毁)。
3. 为什么不会继续执行后续代码?
阻塞特性:joinRpcThreadpool() 是一个阻塞调用,类似于 pthread_join() 或 std::thread::join()。它会挂起当前线程,直到满足退出条件。
线程池生命周期:在 Android 服务中,线程池通常会在服务销毁时(如系统关闭或服务被强制停止)才会退出阻塞状态。
4. 实际效果示例
假设有以下代码:
void startService() { sp service = new AGM(); configureRpcThreadpool(16, true); service->registerAsService(); joinRpcThreadpool(); // 主线程阻塞在这里 LOG("This line will never be executed!"); // 不会执行 }
行为:
主线程调用 joinRpcThreadpool() 后挂起。
客户端的 RPC 请求由线程池中的工作线程处理。
只有当线程池被销毁(如调用 shutdownRpcThreadpool())时,joinRpcThreadpool() 才会返回,主线程继续执行后续代码(但实际很少发生)。
5. 典型应用场景
系统服务:Android 的系统服务(如 SurfaceFlinger、AudioFlinger)通常会在初始化后调用 joinRpcThreadpool(),保持主线程存活以监听请求。
常驻后台服务:需要长期运行的服务通过这种方式避免主线程退出。
总结
阻塞主线程:joinRpcThreadpool() 会阻塞主线程,使其无法继续执行后续代码。
调度者角色:主线程的作用变为等待线程池任务完成,而不是处理具体业务逻辑。
设计意图:确保服务持续运行,直到系统显式销毁它。