从 Remote Service Binding 学习 AIDL 与 IPC

本文深入解析了如何利用AIDL(Android Interface Definition Language)实现Android进程间的通信(IPC),包括创建.AIDL文件、实现接口、公开接口给客户端以及使用Parcelables传递对象等关键步骤。并通过示例代码展示了如何在远程服务中使用AIDL进行通信,并提供了调用IPC方法的完整流程。
 

默认情况下,一个应用不管有多少个 Activity、Service 或其他组件,它们都是运行在一个进程上,但是我们可以安排 Service 运行一个新的进程上,但是不同进程之间应该如何通信呢?当需要在不同的进程之间传递对象时,应该怎么做呢?AIDL(Android Interface Definition Language) 便是解决这一问题的钥匙。

使用 AIDL 并不是难事,但是比较繁琐,并且一不小心容易出错。好在 Android Dev Guide 的 Designing a Remote Interface Using AIDL 对这个问题讲解非常详细,再结合 Android APIDemo 中的 Remote Service Binding 给出了的示例,这都给了开发者提供了非常到位的帮助。以下内容就是我结合二者,整理出来的笔记,力求真理,但能力有限,差错难免,请读者坚持自己的判断力,本文只供参考,且不可尽信。

一、使用 AIDL 实现 IPC

面对问题,应统揽全局,归纳阶段,划定步骤,共得出四大步,分列如下:

创建.aidl 文件
在这个文件里定义 method 和 field
把 .aidl 文件加入到 makefile 中去
如果使用 Eclipse 则 ADT 会帮你管理
实现接口方法
AIDL 编译器会根据接口生成一个用 Java 语言编写的interface,这个 interface 有一个抽象的内部类,名字为 Stub,你必须创建一个类,继承于它,并且实现 .adil 文件中所声明的方法
公开接口给客户端
如果创建的是 service,则应该继承自 Service,并且重载 Service.onBind() 返回实现接口的类的实例

这四个步骤在 Remote Service Binding 中均有所呈现,以下分开阐述。Remote Service Binding 共包含有两个 .java 文件,三个 .aidl 文件,物理结构比较简单,但是逻辑结构就不那么简单,以下用 Class Diagram 来展示其中的关系。

Remote Service Binding

Remote Service Binding

1、创建.aidl 文件

AIDL 语法简单,用来声明接口,其中的方法接收参数和返回值,但是参数和返回值的类型是有约束的,且有些类型是需要 import,另外一些则无需这样做。

AIDL 支持的数据类型划分为四类,第一类是 Java 编程语言中的基本类型,第二类包括 String、List、Map 和 CharSequence,第三类是其他 AIDL 生成的 interface,第四类是实现了 Parcelable protocol 的自定义类。

其中,除了第一类外,其他三类在使用时均需要特别小心。

使用第二类时,首先需要明白这些类不需要 import,是内嵌的。其次注意在使用 List 和 Map 此二者容器类时,需注意其元素必须得是 AIDL 支持的数据类型,List 可支持泛型,但是 Map 不支持,同时另外一端负责接收的具体的类里则必须是 ArrayListHashMap

使用第三、四类时,需要留意它们都是需要 import 的,但是前者传递时,传递的是 reference,而后者则是 value。

在创建 .aidl 文件的过程中,应该注意一旦 method 有参数,则需注意在前面加上 in, out 或 inout,它们被称为 directional tag,但是对于基本类型的参数,默认就是 in,并且不会是其他值。

Remote Service Binding 共包括了三个 .aidl 文件,分别是IRemoteService.aidl、IRemoteServiceCallback.aidl、ISecondary.aidl,通过它们可以看到如何使用第一类和第三类的数据类型,稀罕的是,看不到第二类、第四类数据类型的使用,也没有看到 directional tag。

2、实现 Interface

AIDL 为你生成一个 interface 文件,文件名称和 .aidl 文件相同。如果使用 Eclipse 插件,则 AIDL 会在构建过程中自动运行,如果不使用插件,则需要先使用 AIDL。

生成的 interface 会包含一个抽象内部类 Stub,它声明了在 .aidl 文件里的所有方法。Stub 也定义了一些帮助方法,比较常用的有 asInterface(),其接收一个 IBinder 作为参数,并且返回一个 interface 的实例用来调用IPC方法。

    private static INotificationManager sService;
 
    static private INotificationManager getService()
    {
        if (sService != null) {
            return sService;
        }
        sService = INotificationManager.Stub.asInterface(ServiceManager.getService("notification"));
        return sService;
    }

要实现 interface,需要继承 Stub,实现其方法,这在 RemoteServiceRemoteServiceBinding 都可以找到相关代码。

这个环节是重中之重,需要特别小心的有两点,其一是抛出的所有异常均不会发给调用者;其二是IPC调用是同步的,这意味IPC服务一旦花费较长时间完成的话,就会引起ANR,应该将这样的操作放在单独的线程里。

3、向客户端公开 Interface

独乐乐不如众乐乐,需要将服务公开出去,要达成这个目的,须得创建一个 Service 的子类,并且实现 Service.onBind(Intent),通过这个方法将实现了接口的类的实例返回回来。通过查看 RemoteService 一目了然。

    @Override
    public IBinder onBind(Intent intent) {
        // Select the interface to return.  If your service only implements
        // a single interface, you can just return it here without checking
        // the Intent.
        if (IRemoteService.class.getName().equals(intent.getAction())) {
            return mBinder;
        }
        if (ISecondary.class.getName().equals(intent.getAction())) {
            return mSecondaryBinder;
        }
        return null;
    }

其中的 mBinder 和 mSecondaryBinder 分别是实现了 IRemoteServiceISecondary 接口的类的实例。

4、使用Parcelables传值

前文中提到 Remote Servcie Binding 没有使用第四类数据类型作为参数,这是示例的不足,要想让一个类变成第四类,需要遵照以下步骤:

  1. 引入 Parcelable 接口
  2. 实现 writeToParcel(Parcel out)
  3. 增加一个静态的field,其实现 Parcelable.Creator 接口
  4. 创建一个 .aidl 文件,用以声明你的 parcelables 类

Designing a Remote Interface Using AIDL 中,类 Rect 是一个不错的示例,弥补了 Remote Service Binding 的不足。

二、调用 IPC 方法

万事具备,只欠东风,IPC 备妥,只待调用。在 Remote Service Binding 中,RemoteServiceBinding 正是 IPC 的调用者,

既然要使用接口,那就先声明 interface 类型的变量,

    /** The primary interface we will be calling on the service. */
    IRemoteService mService = null;
    /** Another interface we use on the service. */
    ISecondary mSecondaryService = null;

实现 ServiceConnection,在 onServiceConnected(ComponentName className, IBinder service) 中完成对 mServicemSecondaryService 的赋值。

    private ServiceConnection mConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className,
                IBinder service) {
            mService = IRemoteService.Stub.asInterface(service);
            // ... 以下省略
        }
    }

接着别忘了调用 Context.bindService(),完成任务以后,调用 Context.unbindService()。如果在 connection 中断的情况下,调用 IPC 方法,你会遇到 DeadObjectException,这是 remote method 能抛出的唯一异常。

内容概要:本文针对四机并联孤岛微电网系统,提出了一种融合DoS(拒绝服务)攻击场景、二次控制、下垂控制事件触发式负荷控制的协同控制策略,在Simulink环境中实现了电压频率恢复及有功/无功功率共享分配的仿真验证。研究通过引入混合动态事件触发机制,有效降低控制器间的通信频率网络负载,同时提升系统在面对间歇性通信中断或网络攻击时的鲁棒性容错能力。控制架构采用分层设计,结合多智能体系统(MAS)的分布式协同思想,利用弹性二次控制补偿下垂控制带来的静态偏差,并在DoS攻击导致部分通信链路失效的情况下,保障微电网电能质量运行稳定性。整体方案体现了网络安全性控制性能的深度融合,适用于高比例分布式能源接入场景下的智能微电网安全稳定运行需求。; 适合人群:具备电力电子、自动控制理论微电网运行控制基础知识,熟悉Simulink/MATLAB仿真环境,从事分布式能源系统、智能电网安全控制、网络物理系统(CPS)等领域研究的研究生、科研人员及工程技术人员。; 使用场景及目标:①研究微电网在遭受网络攻击(如DoS)时的动态响应特性稳定性保持能力;②设计低通信开销、高鲁棒性的分布式协同控制策略;③实现孤岛微电网的电压频率精确恢复功率均分控制;④验证事件触发机制在实际控制系统中的节能抗干扰优势。; 阅读建议:建议结合提供的Simulink模型进行仿真实验,重点分析事件触发阈值设置、DoS攻击周期强度对系统性能的影响,深入理解二次控制下垂控制之间的协调逻辑,并可进一步拓展至其他类型网络攻击(如重放攻击、虚假数据注入)的防御机制研究。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值