参考地址: https://zhuanlan.zhihu.com/p/436246818
参考地址: https://blog.csdn.net/qq_30379689/article/details/79451596

手写一个跨进程通信 Binder

代码地址

Binder 是基于 C/S模型

先定义实体类

定义需要在跨进程中传输的数据的数据格式

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
public class Dog implements Parcelable {

private int gender;
private String name;

public Dog(){

}

public int getGender() {
return gender;
}

public void setGender(int gender) {
this.gender = gender;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

protected Dog(Parcel in) {
this.gender = in.readInt();
this.name = in.readString();
}

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

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

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

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

此时实体类一定要实现 Parcelable ,即序列化。

定义接口层IInterface

IInterface 是跨进程通信的中,向外提供的功能接口暴露
在这里需要定义Service需要向外暴露的部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
interface IDogManager : IInterface {

companion object{
val DESCRIPTOR = "com.example.project.Binder.interfaces.IDogManager"

val TRANSACTION_getDogList = IBinder.FIRST_CALL_TRANSACTION + 0

val TRANSACTION_addDog = IBinder.FIRST_CALL_TRANSACTION + 1
}

fun getDogList(): List<Dog>

fun addDog(dog: Dog?)

}
  • 定义了两个函数API,这两个函数会对 client暴露

    • getDogList 获取数据
    • addDog 添加数据
  • 定义了三个静态常量:

    • DESCRIPTOR 标识符
    • TRANSACTION_getDogList 代表调用 getDogList 函数的code
    • TRANSACTION_addDog 代表调用 addDog 函数的code

在跨进程通信中,查看 IInterface 层,就能知道 Service 层对 Client 层暴露的 api。

Binder层

  • 新建类 DogManagerImpl
  • 继承Binder
  • 实现接口层IInterface
  • 新建代理类 Proxy 继承 DogManagerImpl 类
  • 提供 asInterface 函数,对 IBinder 实例对象进行转换

1.新建类 DogManagerImpl

1
abstract class DogManagerImpl{}
  • 此处新建的是抽象类,也可以不用抽象类,但使用抽象类,可以让Service的逻辑写在自己的代码中,使逻辑更加清晰

2.继承Binder

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
abstract class DogManagerImpl : Binder() {
init {
// 相当于注册
attachInterface(this, DESCRIPTOR)
}

// 将当前对象包装成 IBinder
override fun asBinder(): IBinder {
return this
}

override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean {
// 根据code匹配调用对应的函数
when(code){
INTERFACE_TRANSACTION -> {
reply?.writeString(DESCRIPTOR)
return true
}

TRANSACTION_getDogList -> {
// 获取数据时
data.enforceInterface(DESCRIPTOR)
var _result = getDogList()
reply?.writeNoException()
// 输出结果
reply?.writeTypedList(_result)
return true
}

TRANSACTION_addDog -> {
data.enforceInterface(DESCRIPTOR)
var _arg0: Dog? = null
if(data.readInt() != 0) {
_arg0 = Dog.CREATOR.createFromParcel(data)
} else {
_arg0 = null
}
addDog(_arg0)
reply?.writeNoException()
return true
}

}
return super.onTransact(code, data, reply, flags)
}
}

3.实现接口层IInterface

1
abstract class DogManagerImpl : Binder(), IDogManager{}

因为 DogManagerImpl 被定义成抽象类,所以此处只需写 实现 IDogManager 即可,无需实现具体函数

4. 新建代理类 Proxy 继承 DogManagerImpl 类

新建一个静态内部类 Proxy 继承 DogManagerImpl

因为 DogManagerImpl 是抽象类,所以还要实现 getDogList 、 addDog 函数

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
companion object {
class Proxy(var remote: IBinder) : DogManagerImpl() {

override fun asBinder(): IBinder {
return remote
}

override fun getInterfaceDescriptor(): String {
return DESCRIPTOR
}

override fun getDogList(): List<Dog> {
var _data = Parcel.obtain()
var _reply = Parcel.obtain()
var _result: java.util.ArrayList<Dog>? = null
try {
_data.writeInterfaceToken(DESCRIPTOR)
remote.transact(TRANSACTION_getDogList,_data,_reply,0)
_reply.readException()
_result = _reply.createTypedArrayList(Dog.CREATOR)
println("proxy getData => ${_result}")
}catch (e: Exception) {
e.printStackTrace()
println("error => ${e.message}")
}finally {
_data.recycle()
_reply.recycle()
}
return _result!!.toList()
}

override fun addDog(dog: Dog?) {
var _data = Parcel.obtain()
var _reply = Parcel.obtain()
try {
_data.writeInterfaceToken(DESCRIPTOR)
if(dog != null) {
_data.writeInt(1)
dog.writeToParcel(_data,0)
} else {
_data.writeInt(0)
}
remote.transact(TRANSACTION_addDog, _data, _reply, 0)
println("proxy addDog => ${_data}")
_reply.readException()
}catch (e: Exception) {
e.printStackTrace()
}finally {
_data.recycle()
_reply.recycle()
}
}

}
}

此处的 Proxy 类其实就是跨进程通信中 会被使用的类

5. 提供 asInterface 函数,对 IBinder 实例对象进行转换

  • 在 companion object 代码块中添加一个 静态函数 asInterface
1
2
3
4
5
6
7
8
9
10
11
12
13
14
companion object {
fun asInterface(binder: IBinder):IDogManager? {
if(binder == null) return null
var iin = binder.queryLocalInterface(DESCRIPTOR)
if(iin != null && iin is IDogManager) {
// 在同一进程时,直接返回对象
println("在统一进程时,直接返回对象")
return iin
}
// 不在同一进程,返回代理对象
println("不在同一进程,返回代理对象")
return Proxy(binder)
}
}

这里可以看出 asInterface 函数功能就是通过 IBinder 实例,转换为对应的接口实例

注意此处关于进程的判断
当 client 与 service 处于相同进程时,则直接返回该对象
当处于不同进程时,返回的是 Proxy 实例

Service层代码

  • 接下来编写 Service 代码
    • 注册一个系统服务Service
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class RemoteService: Service() {

var dogs = ArrayList<Dog>()

val mBinder = object : DogManagerImpl() {
override fun getDogList(): List<Dog> {
println("RemoteService => getDogList: ${dogs}")
return dogs
}

override fun addDog(dog: Dog?) {
if(dog != null) {
dogs.add(dog)
}
}

}

override fun onBind(intent: Intent?): IBinder? {
return mBinder
}
}
  • 在 AndroidManifest.xml 中的配置
1
2
3
4
5
<application>
<service android:name=".Binder.RemoteService"
android:process=":remote"
></service>
</application>
  • 注意此处的 android:process=”:remote”, 这是指定 service 运行进程为 包名 + :remote

    process 用于指定进程名,默认与包名一致