Android之 从AIDL说说Binder

请尊重原创,转载请注明出处【tianyl】的博客

前言

说到Android,有一个绕不过去的知识点就是IPC,也叫进程间通信,鉴于市面上已经很多Binder的深入解析,这里我也不说重复的话了,感觉从AIDl的角度聊聊BInder(因为我看好像很少有博客从这个角度切入)

本文概要

1 什么是Binder
2 什么Android要使用Binder作为IPC的方式?Linux现有的IPC方式不能用吗
3 什么是AIDL,AIDL和BInder又是什么关系
4 AIDL的基础用法
5 什么是Stub和Proxy,它们又是如何通信的?

1 什么是Binder

Binder是Android系统进程间通信(IPC)方式之一,说到IPC,就要介绍一些Linux中的IPC方式

2 Linux的IPC方式

  • 管道(Pipe)
    • 一个线性的内存区域,存消息时将数据写入管道,取消息时从管道拷贝数据,因为有两次拷贝(效率低)
  • 插口(Socket)
    • 是一个通用接口,导致其传输效率低,开销大,有两次拷贝(效率低)
  • 报文队列(Message)
    • 有两次拷贝(效率低)
  • 共享内存(Share Memory)
    • 机制复杂,管理内存机制复杂
  • 信号量(Semaphore)
  • 信号(Signal)
  • 跟踪(Trace)

3 Binder

3.1 Binder的优点

  • 安全性
    • Linux的IPC机制在本身的实现中,并没有安全措施,得依赖上层协议来进行安全控制。而Binder机制的UID/PID是由Binder机制本身在内核空间添加身份标识,安全性高
  • 私有管道
    • Binder可以建立私有通道,这是linux的通信机制所无法实现的(Linux访问的接入点是开放的)
  • 效率性
    • LInux原有的IPC方式,要么是需要多次拷贝(2次或2次以上),要么则是机制复杂,而BInder只需要一次拷贝,在多线程时管理内存也相对容易

所以从效率上和安全性上考虑,Google摒弃了LInux的IPC方式,重新构建了一套属于Android的IPC方式——BInder

4 Binder和AIDL

AIDL全称:Android Interface Definition Language,Binder是IPC的机制,AIDL是Binder的具体规范

5 AIDL详解

关于AIDL,它是Android Interface Definition Language,对于一个.aild文件,它经过IDE的处理后,会生成一个java文件

这个java类会实现android.os.IInterface接口,并且含有一个Stub的静态抽象内部类

public interface IAIDLTest extends android.os.IInterface

5.1 Stub

仔细查看抽象类Stub,它继承了android.os.Binder,并实现了我们定义的AIDL接口

public static abstract class Stub extends android.os.Binder implements com.demo.tianyl.demo.IAIDLTest

5.2 Proxy

Proxy是抽象类Stub中的一个静态内部类,它也实现了我们定义的AIDL接口

private static class Proxy implements com.demo.tianyl.demo.IAIDLTest

5.3 Stub和Proxy

介绍完了Stub和Proxy的类的定义,下面来说说AIDL使用时它们之间的关系

1

首先要从我们定义的AIDL说起了,如果我们要使用AIDL,那么我们首先需要定义一个AIDL接口文件(IAidlTest.aidl),根据这个.aidl文件自动生成一个.java文件,并且构建一个Service实现我们定义的AIDL接口(AidlTestService.java),并且在manifest中注册这个服务

2

在其他的进程,需要使用AIDL的地方,调用bindService开启这个服务,然后在ServiceConnection中处理返回的IBinder对象

//开启服务
bindService(service, mConnection, Context.BIND_AUTO_CREATE);

//处理IBinder对象
IAIDLTest mService = null
private ServiceConnection mConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        mService = IAIDLTest.Stub.asInterface(service)
    }
    @Override
    public void onServiceDisconnected(ComponentName name) {
        mService = null
    }
};

3

说完了用法,下面来解析

首先在bindService中,获得我们在AidlTestService.java(aidl实现类)中的onBind方法中返回的IBinder

实现类一般写法如下

public class AidlTestService extends Service {

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

    IAIDLTest.Stub mBinder = new IAIDLTest.Stub() {
        //do something
    };
}

4

然后在ServiceConnection中,处理上面返回的IBinder

mService = IAIDLTest.Stub.asInterface(service)

看内部类Stub中的方法asInterface

public static com.demo.tianyl.demo.IAIDLTest asInterface(android.os.IBinder obj) {
    if ((obj == null)) {
        return null;
    }
    android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
    if (((iin != null) && (iin instanceof com.demo.tianyl.demo.IAIDLTest))) {
        return ((com.demo.tianyl.demo.IAIDLTest) iin);
    }
    return new com.demo.tianyl.demo.IAIDLTest.Stub.Proxy(obj);
}

asInterface方法会根据当前的进程还决定返回Stub或者Proxy

  • 如果当前进程和AIDL定义的进程相同,就返回Stub的实现类(AidlTestService.java)
  • 如果当前进程和AIDL定义的进程不同,就返回Proxy

所以我们可以猜到,AidlTestService.java是Stub的真实实现类,Proxy是Stub在其他进程的代理实现类

5.4 Stub和Proxy的通信

说完了Stub和Proxy的关系,再说说它们是如何通信的

既然Proxy是Stub在其他进程的实现类,那么其他进程在调用AIDL接口中的方法时,肯定是通过Proxy进行的,例如一个求和方法add

1

Proxy中的方法如下

@Override
public int add(int x, int y) 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(x);
        _data.writeInt(y);
        mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
        _reply.readException();
        _result = _reply.readInt();
    } finally {
        _reply.recycle();
        _data.recycle();
    }
    return _result;
}

这个方法主要做了2件事

  1. 序列化参数x和y
  2. 调用mRemote.transact方法

其中Stub.TRANSACTION_add是定义的一个标准常量,用于确定调用的是哪个方法

static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);

2

从mRemote的transact,会回调到Stub的onTransact,在这个方法中,会有

@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_add: {
            data.enforceInterface(descriptor);
            int _arg0;
            _arg0 = data.readInt();
            int _arg1;
            _arg1 = data.readInt();
            int _result = this.add(_arg0, _arg1);
            reply.writeNoException();
            reply.writeInt(_result);
            return true;
        }
        default: {
            return super.onTransact(code, data, reply, flags);
        }
    }
}

在TRANSACTION_add分支中,会将参数反序列化,然后调用this.add(_arg0, _arg1),就是它的实现类,然后将结果回传回去

6 总结

关于AIDL和Binder的相关描述,到此就结束了,因为考虑到已经有不少源码分析的博客,所以这里就较少的涉及源码方面,想必开篇的问题,大家心中已经有答案了吧

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,367评论 6 512
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,959评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,750评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,226评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,252评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,975评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,592评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,497评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,027评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,147评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,274评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,953评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,623评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,143评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,260评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,607评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,271评论 2 358