Android Binder知识点梳理 -- 从AIDL谈起

Binder在Android中就像血液一样,流淌在各个模块之间,HIDL的添加有使血液流向了硬件抽象层(HAL)部分,如果没有理解Binder,那么当看其他模块时会总觉得云里雾里,不能说真的理解了这个模块。刚开始接触Android是从开发app开始的,一路做到FW,而APP中使用Binder跨应用的方法就是AIDL了。所以打算从AIDL作为起点,记录一下自己对Binder的理解。

Binder的实现方式

因为Android是多层的结构,从Android的AOSP介绍中我们可以知道

image

从图中可以看出整个Android系统实际上是在Linux kernel的基础上叠加起来的,像搭建积木一样,当然不会看着这么规整。那么Android的内存管理,进程调度其实都离不开kernel的支持,使用的一些安全和进程策略都和Linux Kernel有着千丝万缕的联系。Linux中进程间通信(IPC)的方式一般包括:管道(PIPE)、Socket、内存共享、FIFO、消息队列、信号等,这些在大学都有学习。但是Android为什么没有用其中的一直用作为主力呢,主要是因为Android开发之初,Google有个叫做乔治霍夫曼(George Hoffman)的原Be公司工程师,他在OpenBinder的基础上开发Android Binder,用来管理Android进程(这个在网上也是能搜索到的),因此一直沿用到现在。Google模仿Binder在FW和HAL层之间添加了HIDL来通信,HIDL的也是Binder。当然其实SOCKET、PIPE在Android中也是使用的,看源码的话,在Native层我们也是能够看到他们被使用的。只不过Binder不仅仅在Native层,在FW层和APP层(Java编写)都有实现。实FW层和APP层的使用都是在Native层和kernel驱动的基础上的,没有底层,上层是做不到的。这样又回到上图中的层级结构,跨进程的RPC,贯穿了上图中Android整个的层级结构。而AIDL的使用使APP开发者不管底层的实现,底层的实现对APP开发时透明的,只需要在aidl文件中定义简单的接口,就可以实现跨进程。

AIDL接口定义

1
2
3
4
5
6
7
8
9
10
11
12
// IMyService.aidl
package com.test.test;

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

interface IMyService {

void printHello();
void printSomething(String some);
String getString();

}

生成Java文件解析

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
/*
* This file is auto-generated. DO NOT MODIFY.
* Original file: C:\\Users\\yin_q\\Documents\\FooTest\\myapplication\\src\\main\\aidl\\com\\test\\test\\IMyService.aidl
*/
package com.test.test;
// Declare any non-default types here with import statements


public interface IMyService extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.example.yoon.myapplication.IMyService
{
private static final java.lang.String DESCRIPTOR = "com.example.yoon.myapplication.IMyService";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.example.yoon.myapplication.IMyService interface,
* generating a proxy if needed.
*/
public static com.test.test.asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.example.yoon.myapplication.IMyService))) {
return ((com.example.yoon.myapplication.IMyService)iin);
}
return new com.test.test.myapplication.IMyService.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;
}
case TRANSACTION_printHello:
{
data.enforceInterface(DESCRIPTOR);
this.printHello();
reply.writeNoException();
return true;
}
case TRANSACTION_printSomething:
{
data.enforceInterface(DESCRIPTOR);
java.lang.String _arg0;
_arg0 = data.readString();
this.printSomething(_arg0);
reply.writeNoException();
return true;
}
case TRANSACTION_getString:
{
data.enforceInterface(DESCRIPTOR);
java.lang.String _result = this.getString();
reply.writeNoException();
reply.writeString(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.example.yoon.myapplication.IMyService
{
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 printHello() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_printHello, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
@Override public void printSomething(java.lang.String some) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeString(some);
mRemote.transact(Stub.TRANSACTION_printSomething, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
@Override public java.lang.String getString() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.lang.String _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getString, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
static final int TRANSACTION_printHello = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_printSomething = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
static final int TRANSACTION_getString = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
}
public void printHello() throws android.os.RemoteException;
public void printSomething(java.lang.String some) throws android.os.RemoteException;
public java.lang.String getString() throws android.os.RemoteException;
}

这个文件看起来比较乱,其实IMyService接口中主要关注两个类: IMyService.Stub(抽象类)和IMyService.Stub.Proxy(静态类)

image

IMyService.Stub

作为服务侧的抽象类,需要在app的service中进行继承才能使用,因为又实现了IMyService接口,所以需要实现IMyService接口中的接口,而这里的接口就是Service提供给客户端的功能接口,也就是在AIDL中定义的。此类还继承了Binder,所以override了onTransact方法,onTransact中会根据不同的code去执行不同的case,case中最终调用的就是我们在app service中实现的Stub子类,同时也就是在AIDL定义的接口,这样就完成了客户端对Service的调用,但是onTransact是被谁调用的呢,可以肯定的是客户端调用,但是怎么调用到这里的?这个稍后会介绍,我们看一下一个重要的方法:asInterface()

1
2
3
4
5
6
7
8
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.example.yoon.myapplication.IMyService))) {
return ((com.example.yoon.myapplication.IMyService)iin);
}
return new com.example.yoon.myapplication.IMyService.Stub.Proxy(obj);

这个方法在app开发中会在ServiceConnection的onServiceConnected方法中调用,返回的IBinder作为参数。 因为我们在开发app时,有时需要把Service和Client写在同一个app中,比如音乐播放,把长时间没有UI的逻辑放到Service中执行,这样onServiceConnected返回的就在同一个进程中的(在同一个虚拟机中),因此iin instanceof com.example.yoon.myapplication.IMyService分支就会成立,所以直接使用obj就好,但是如果是另一个应用提供的Service,那就是两个进程之间的调用,因此走的另一个分支,将obj封装到了Proxy类中。

IMyService.Proxy

obj被封装到此类中,Proxy只是一个框架,真正调用的是里面的mRemote,也就是onServiceConnected中获得的所要使用的Service的Proxy(代理),最终调用的是mRemote的transact方法,并将参数封装到Parcel中,传递了出去。transact又做了什么?这个要在Java层Binder通信中描述清楚了。