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

你可能感兴趣的:(Android之 从AIDL说说Binder)