Binder 是什么

首先在 Android 中, Binder 是一个类,实现了 IBinder 接口, 是实现跨进程通信 (IPC)的一种方式

为什么需要跨进程通信

因为在 Android 中一个应用相当于一个进程,而一个进程中有一个独立的用户空间,而用户空间都是独立的,进程之间是隔离的。也就是说,两个进程之间不可进行直接的通信,需要通过一个桥梁,这个就是 Binder

Android 为什么要使用 Binder

在跨进程通信的方式中,有几种方式,为什么要在 Android 中使用 Binder 机制呢 ?

首先通过一个图来看看传统的 IPC 的通信机制的方式

传统的 IPC 通信方式需要通过用户空间发送数据,通过系统调用 copy_form_user 将数据复制到内核缓存区,而另外一个进程还需要使用的话,则还需要再将内核空间的数据再次拷贝到另外一个进程的用户空间上去,这里拷贝了两次。而如果相较于 Binder 的话, Binder 只拷贝了一次,Binder 的效率会比传统的 IPC 通信效率更高,下面图示 Binder 的通信过程

Binder 通信过程

Binder 通信方式的过程中,是只需要拷贝一次数据的,将用户空间的数据拷贝到内核缓存区中。而由于存在内存映射的关系 (mmap)内核缓冲区和数据接收缓存区存在内存映射的关系,无需拷贝,可对对象直接引用

Binder 与传统 IPC 优缺点

一共有如下的 3 种 IPC 通信方式

  • 共享内存
  • Socket
  • Binder

Binder 基于 C/S 架构,客户端(Client)有什么需求就丢给服务端(Server)去完成,架构清晰、职责明确又相互独立,自然稳定性更好。共享内存虽然无需拷贝,但是控制负责,难以使用。从稳定性的角度讲,Binder 机制是优于内存共享的。

另一方面就是安全性。Android 作为一个开放性的平台,市场上有各类海量的应用供用户选择安装,因此安全性对于 Android 平台而言极其重要。作为用户当然不希望我们下载的 APP 偷偷读取我的通信录,上传我的隐私数据,后台偷跑流量、消耗手机电量。传统的 IPC 没有任何安全措施,完全依赖上层协议来确保。首先传统的 IPC 接收方无法获得对方可靠的进程用户ID/进程ID(UID/PID),从而无法鉴别对方身份。Android 为每个安装好的 APP 分配了自己的 UID,故而进程的 UID 是鉴别进程身份的重要标志。传统的 IPC 只能由用户在数据包中填入 UID/PID,但这样不可靠,容易被恶意程序利用。可靠的身份标识只有由 IPC 机制在内核中添加。其次传统的 IPC 访问接入点是开放的,只要知道这些接入点的程序都可以和对端建立连接,不管怎样都无法阻止恶意程序通过猜测接收方地址获得连接。同时 Binder 既支持实名 Binder,又支持匿名 Binder,安全性高。

AIDL 实现

首先创建一个 Service 和一个 AIDL 接口,接着创建一个类继承自 AIDL 接口中的 Stub 类并实现 Stud 中的抽象方法,在 Service 的 onBind 方法中返回这个类的对象,然后客户端就可以绑定服务端的 Service,建立连接后就可以访问远程服务端的方法了

首先在服务端中先定义一个 Person 对象,需要实现序列化

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
public class Person implements Parcelable {

    private String name;

    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }


    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }


    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(this.name);
        dest.writeInt(this.age);
    }

    protected Person(Parcel in) {
        this.name = in.readString();
        this.age = in.readInt();
    }

    public static final Creator<Person> CREATOR = new Creator<Person>() {
        @Override
        public Person createFromParcel(Parcel source) {
            return new Person(source);
        }

        @Override
        public Person[] newArray(int size) {
            return new Person[size];
        }
    };
}

然后再定义通信接口 AIDL 文件,注意如果是使用到了自定义的 Person 类,需要在 AIDL 文件中先声明

Person.aidl
1
2
3
4
5
6
// Person.aidl
package com.midfang.service.bean;

// Declare any non-default types here with import statements

parcelable Person; // 声明

IDefaultAidlInterface

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
package com.midfang.service;

// Declare any non-default types here with import statements

// 自定义的类,需要手动导入
import com.midfang.service.bean.Person;

interface IDefaultAidlInterface {

     // in 表示数据只能由客户端流向服务端
     // out 表示数据只能由服务端流向客户端
     // inout 则表示数据可以在服务端与客户端之间双向流通
     void addPerson(in Person person);

     List<Person> getPersonList();
}

定义服务端 service

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class MyService : Service() {

    private val TAG = "MyService"

    private val mutableList = mutableListOf<Person>()

    override fun onBind(p0: Intent?): IBinder? {
        Log.d(TAG, "onBind() called with: iBinder = $iBinder")
        return iBinder
    }

    private val iBinder = object : IDefaultAidlInterface.Stub() {
        override fun addPerson(person: Person) {
            Log.d(TAG, "addPerson() called with: person = ${person.toString()}")
            mutableList.add(person)
        }

        override fun getPersonList(): MutableList<Person> {
            Log.d(TAG, "getPersonList() called ${mutableList.toString()}")
            return mutableList
        }
    }

    override fun onCreate() {
        super.onCreate()
        Log.d(TAG, "onCreate() called")

    }
}

定义客户端代码

客户端的代码,一样需要定义同样一套 AIDL 接口协议, 注意包名路径需要一致

1
2
3
4
5
6
// Person.aidl
package com.midfang.service.bean;

// Declare any non-default types here with import statements

parcelable Person;
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
package com.midfang.service;

// Declare any non-default types here with import statements

import com.midfang.service.bean.Person;

interface IDefaultAidlInterface {

     // in 表示数据只能由客户端流向服务端
     // out 表示数据只能由服务端流向客户端
     // inout 则表示数据可以在服务端与客户端之间双向流通
     void addPerson(in Person person);

     List<Person> getPersonList();
}

这两个类的定义,其实和服务端中的一模一样

绑定服务

然后在定义客户端中的和服务端通信的代码, 绑定服务

1
2
3
4
5
6
val intent = Intent()
intent.component = ComponentName(
        "com.midfang.aidl_service",
        "com.midfang.service.MyService"
)
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE)

获得句柄,拿到服务端中 onBinder 返回的对象

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
private var iBinder: IDefaultAidlInterface? = null

    private val serviceConnection = object : ServiceConnection {
        override fun onServiceDisconnected(p0: ComponentName?) {
            Log.d(TAG, "onServiceDisconnected() called with: p0 = $p0")
            iBinder = null
        }

        override fun onServiceConnected(p0: ComponentName?, p1: IBinder?) {
            Log.d(TAG, "onServiceConnected() called with: p0 = $p0, p1 = $p1")

						// 服务连接成功后,会返回实例对象
            iBinder = IDefaultAidlInterface.Stub.asInterface(p1)
        }
    }

源码分析

大致看看 IDefaultAidlInterface 里面都做了什么操作

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/*
 * This file is auto-generated.  DO NOT MODIFY.
 * Original file: /Users/apple/asDemo/aidl_client/src/main/aidl/com/midfang/service/IDefaultAidlInterface.aidl
 */
package com.midfang.service;

public interface IDefaultAidlInterface extends android.os.IInterface {
    /**
     * Local-side IPC implementation stub class.
     */
    public static abstract class Stub extends android.os.Binder implements com.midfang.service.IDefaultAidlInterface {
        private static final java.lang.String DESCRIPTOR = "com.midfang.service.IDefaultAidlInterface";

        /**
         * Construct the stub at attach it to the interface.
         */
        public Stub() {
        		// 设置了一个 描述符,后续可以根据描述符查询对应的服务,或者校验
            this.attachInterface(this, DESCRIPTOR);
        }

        /**
         * Cast an IBinder object into an com.midfang.service.IDefaultAidlInterface interface,
         * generating a proxy if needed.
         */
        public static com.midfang.service.IDefaultAidlInterface asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            // 查询关于这个描述符的 服务
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof com.midfang.service.IDefaultAidlInterface))) {
            		// 不属于进程间通信,直接建立通信
                return ((com.midfang.service.IDefaultAidlInterface) iin);
            }
            // 属于进程间通信,开启 proxy 的代理
            return new com.midfang.service.IDefaultAidlInterface.Stub.Proxy(obj);
        }

        @Override
        public android.os.IBinder asBinder() {
            return this;
        }

        @Override
        public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
            switch (code) {
                case INTERFACE_TRANSACTION: {
                    reply.writeString(DESCRIPTOR);
                    return true;
                }
                // 定义好的 addPerson 方法
                case TRANSACTION_addPerson: {
                		// 检验
                    data.enforceInterface(DESCRIPTOR);
                    com.midfang.service.bean.Person _arg0;
                    if ((0 != data.readInt())) {
                        _arg0 = com.midfang.service.bean.Person.CREATOR.createFromParcel(data);
                    } else {
                        _arg0 = null;
                    }
                    // 写入数据
                    this.addPerson(_arg0);
                    reply.writeNoException();
                    return true;
                }
                case TRANSACTION_getPersonList: {
                // 校验
                    data.enforceInterface(DESCRIPTOR);
                    // 获取了 personList
        
                    java.util.List<com.midfang.service.bean.Person> _result = this.getPersonList();
                    reply.writeNoException();
                    reply.writeTypedList(_result);
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }

        private static class Proxy implements com.midfang.service.IDefaultAidlInterface {
            private android.os.IBinder mRemote;

            Proxy(android.os.IBinder remote) {
                mRemote = remote;
            }

            @Override
            public android.os.IBinder asBinder() {
                return mRemote;
            }

            public java.lang.String getInterfaceDescriptor() {
                return DESCRIPTOR;
            }

            @Override
            public void addPerson(com.midfang.service.bean.Person person) throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                try {
                		// 校验
                    _data.writeInterfaceToken(DESCRIPTOR);
                    if ((person != null)) {
                        _data.writeInt(1);
                        person.writeToParcel(_data, 0);
                    } else {
                        _data.writeInt(0);
                    }
                    // 调用 Stub 类中的 Stub.TRANSACTION_addPerson 方法
                    mRemote.transact(Stub.TRANSACTION_addPerson, _data, _reply, 0);
                    _reply.readException();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }

            @Override
            public java.util.List<com.midfang.service.bean.Person> getPersonList() throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                java.util.List<com.midfang.service.bean.Person> _result;
                try {
                // 校验
                    _data.writeInterfaceToken(DESCRIPTOR);
                    // 调用 stub 中的方法
                    mRemote.transact(Stub.TRANSACTION_getPersonList, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.createTypedArrayList(com.midfang.service.bean.Person.CREATOR);
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
        }

// 定义的方法的序号,依次累加的
        static final int TRANSACTION_addPerson = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
        static final int TRANSACTION_getPersonList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
    }
    
    public void addPerson(com.midfang.service.bean.Person person) throws android.os.RemoteException;

    public java.util.List<com.midfang.service.bean.Person> getPersonList() throws android.os.RemoteException;
}