【Android】AIDL之一个简单的demo

06-01 1102阅读

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()(自动生成)接收结果。

【Android】AIDL之一个简单的demo
(图片来源网络,侵删)

关键点说明

AIDL 生成代码:编译后,AIDL 工具会自动生成 IAGM.Stub 和 IAGM.Stub.Proxy 类,处理 RPC 通信。

【Android】AIDL之一个简单的demo
(图片来源网络,侵删)

线程池:服务端默认使用 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() 会阻塞主线程,使其无法继续执行后续代码。

调度者角色:主线程的作用变为等待线程池任务完成,而不是处理具体业务逻辑。

设计意图:确保服务持续运行,直到系统显式销毁它。

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们。

目录[+]

取消
微信二维码
微信二维码
支付宝二维码