前面介绍的通过ServiceManager添加服务和获取服务,这些服务都是有名称的,我们可以通过ServiceManager来获取它。除此之外Android系统中还有一类Binder服务是匿名它,它们如何让客户端获得代理对象,并且使用呢,本文就一探究竟。
AIDL 介绍#
AIDL全称为Android接口定义语言,是Android系统提供的一款可供用户用来抽象IPC的工具,它提供了语法让我们来定义跨进程通讯的服务接口,也就是.aidl文件,它也提供了工具,帮助我们把定义文件专程目标语言的代码。
我们自己使用AIDL创建的服务,或者一部分系统内的服务,比如IWindowSession、IApplicationThread等,这些多是运行在App进程,一般都不是系统服务,因此都是匿名的。我们这里以IApplicationThread来分析AIDL创建的匿名服务是怎么传递Binder给使用端的。
以IApplicationThread来分析,则服务端是我们的App进程,而客户端则是system_server进程。作为AIDL创建的Binder,首先会有一个AIDL文件,这里是IApplicationThread.aidl,其中定义了一些跨进程调用的方法,部分内容如下:
package android.app;
...
oneway interface IApplicationThread {
void scheduleReceiver(in Intent intent, in ActivityInfo info,
in CompatibilityInfo compatInfo,
int resultCode, in String data, in Bundle extras, boolean sync,
int sendingUser, int processState);
@UnsupportedAppUsage
void scheduleStopService(IBinder token);
...
}
当前Android AIDL已经支持生成Java、C++、Rust的代码,对于IApplicationThread这里我们只需关注生成Java版本的代码即可。生成的代码在IApplicationThread当中,大概如下所示:
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
| public interface IApplicationThread extends android.os.IInterface {
public static class Default implements android.app.IApplicationThread {
@Override
public void scheduleReceiver(android.content.Intent
...) throws android.os.RemoteException {}
@Override
public android.os.IBinder asBinder() {
return null;
}
}
public abstract static class Stub extends android.os.Binder
implements android.app.IApplicationThread {
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
public static android.app.IApplicationThread asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof android.app.IApplicationThread))) {
return ((android.app.IApplicationThread) iin);
}
return new android.app.IApplicationThread.Stub.Proxy(obj);
}
@Override
public android.os.IBinder asBinder() {
return this;
}
public static java.lang.String getDefaultTransactionName(int transactionCode) {
switch (transactionCode) {
case TRANSACTION_scheduleReceiver:{
return "scheduleReceiver";
}
case TRANSACTION_scheduleCreateService: {
return "scheduleCreateService";
}
default: {
return null;
}
}
}
public java.lang.String getTransactionName(int transactionCode) {
return this.getDefaultTransactionName(transactionCode);
}
@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;
if (code >= android.os.IBinder.FIRST_CALL_TRANSACTION
&& code <= android.os.IBinder.LAST_CALL_TRANSACTION) {
data.enforceInterface(descriptor);
}
switch (code) {
case INTERFACE_TRANSACTION:{
reply.writeString(descriptor);
return true;
}
}
switch (code) {
case TRANSACTION_scheduleReceiver:{
android.content.Intent _arg0;
_arg0 = data.readTypedObject(android.content.Intent.CREATOR);
...
int _arg8;
_arg8 = data.readInt();
data.enforceNoDataAvail();
this.scheduleReceiver(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8);
break;
}
...
default:{
return super.onTransact(code, data, reply, flags);
}
}
return true;
}
private static class Proxy implements android.app.IApplicationThread {
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 scheduleReceiver(
android.content.Intent intent,
...
int processState) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
...
_data.writeTypedObject(intent, 0);
boolean _status = mRemote.transact(
Stub.TRANSACTION_scheduleReceiver, _data, null, android.os.IBinder.FLAG_ONEWAY);
} finally {
_data.recycle();
}
}
...
}
public static final java.lang.String DESCRIPTOR = "android.app.IApplicationThread";
static final int TRANSACTION_scheduleReceiver = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_scheduleCreateService = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
...
public int getMaxTransactionId() {
return 57;
}
}
...
public void scheduleReceiver(
android.content.Intent intent,
...
int processState)
throws android.os.RemoteException;
}
|
对于Java代码,AIDL会生成一个跟AIDL同名的接口,同时继承自IInterface,同时还会创建内部类,分别为Default和Stub。Default为默认实现,大多数情况下是没有的,因为我们自己会实现。而Stub为抽象类,我们自己实现的时候会使用它,它以及继承自Binder,AIDL工具帮助我们把Parcel读写相关的代码已经生成,我们只需要去继承它,实现业务逻辑即可。而Stub中还有一个内部类Proxy,这个类用于Binder服务的客户端使用。对于IApplicationThread的实现,在ActivityThread当中。
匿名服务的传输#
那么ActivityServiceManager(之后简称AMS)是怎么拿到ApplicationThread的呢,ActivityThread的attach方法则是这一切的入口:
1
2
3
4
5
6
| final IActivityManager mgr = ActivityManager.getService();
try {
mgr.attachApplication(mAppThread, startSeq);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
|
代码中,首先拿到AMS的binder客户端类,这里也就是IActivityManager$Stub$Proxy,因为它也用了AIDL,所以跟我们ApplicationThread的类是类似的,具体如何拿到的,这个之前ServiceManager分析getService的时候已经分析过了,这里不看了。我们可以看一下它的attachApplication方法,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| @Override public void attachApplication(android.app.IApplicationThread app, long startSeq) 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.writeStrongInterface(app);
_data.writeLong(startSeq);
boolean _status = mRemote.transact(Stub.TRANSACTION_attachApplication, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
|
这里也是跟我们之前addService类似,把binder写入到Parcel中去,因为App进程这里相当于是ApplicationThread它的服务端,因此这里写入的type为BINDER_TYPE_BINDER,而调用mRemote.transact则为调用BinderProxy的同名方法,我们知道最终会调用到IPCThreadState的transact方法,从而调用binder驱动。
类似于getService的方法,AMS所在的system_server进程会收到BR_TRANSACTION命令,在其中解析数据知道调用的是TRANSACTION_attachApplication这个业务命令,进而使用readStrongInterface来获取到binder的代理对象BinderProxy。具体代码在IActivityManager.Stub的onTransact中,代码如下:
1
2
3
4
5
6
7
8
9
10
11
| case TRANSACTION_attachApplication:
{
android.app.IApplicationThread _arg0;
_arg0 = android.app.IApplicationThread.Stub.asInterface(data.readStrongBinder());
long _arg1;
_arg1 = data.readLong();
data.enforceNoDataAvail();
this.attachApplication(_arg0, _arg1);
reply.writeNoException();
break;
}
|
到这样调用AMS服务端的attachApplication的时候就能使用IApplicationThread所提供的方法了。
Binder驱动中binder节点的处理#
但是看到这里,有个问题,就是我们是匿名的binder,驱动怎么是处理的呢。这个需要去看一下binder驱动的源码,不过就不具体看调用流程了,直接看生成创建node和handle部分的代码:
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
| static int binder_translate_binder(struct flat_binder_object *fp,
struct binder_transaction *t,
struct binder_thread *thread)
{
struct binder_node *node;
struct binder_proc *proc = thread->proc;
struct binder_proc *target_proc = t->to_proc;
struct binder_ref_data rdata;
int ret = 0;
node = binder_get_node(proc, fp->binder);
if (!node) {
node = binder_new_node(proc, fp);
if (!node)
return -ENOMEM;
}
...
ret = binder_inc_ref_for_node(target_proc, node,
fp->hdr.type == BINDER_TYPE_BINDER,
&thread->todo, &rdata);
...
if (fp->hdr.type == BINDER_TYPE_BINDER)
fp->hdr.type = BINDER_TYPE_HANDLE;
else
fp->hdr.type = BINDER_TYPE_WEAK_HANDLE;
fp->binder = 0;
fp->handle = rdata.desc;
fp->cookie = 0;
...
done:
binder_put_node(node);
return ret;
}
|
可以看到对于通过Parcel调用经过binder驱动的binder对象,binder驱动都会给他们创建一个binder_node,并且为其设置handle,在传输到客户端的时候还会把type设置为BINDER_TYPE_HANDLE。
这样我们就对整给流程有所了解了,如果读者还想窥探更多的细节,则需要自行去阅读binder驱动的源码了。
开发者如何使用匿名服务#
这上面介绍的部分是我们使用系统的服务来获取AIDL创建的服务,对于应用开发者来说有什么办法呢。我们可以通过AIDL+Service来实现,Android的四大组件之一的Service,它提供了通过bindService的方式来启动服务。在它的onBind中就可以返回IBinder,Android Framework会帮助我们调用操作代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| private void handleBindService(BindServiceData data) {
CreateServiceData createData = mServicesData.get(data.token);
Service s = mServices.get(data.token);
if (s != null) {
try {
....
try {
if (!data.rebind) {
IBinder binder = s.onBind(data.intent);
ActivityManager.getService().publishService(
data.token, data.intent, binder);
} else {
...
}
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
} catch (Exception e) {
....
}
}
}
|
可以看到在ActivityThread的handleBindService方法 中,我们在拿到Service所提供的IBinder之后,AMS会调用publishService,我们可以在ServiceConnection回调中拿到Binder的代理对象,之后就可以进行跨进程通讯了。
另外Android Framework还为我们提供了Messenger,其实现为Service+AIDL+Handler,让我们不用自己写AIDL,我们自己定义Service的时候使用Messenger和Handler就可以实现跨进程通信了。
到此为止,我们已经分析了Binder服务管家ServiceManager的启动、使用ServiceManger添加服务和查找服务以及匿名服务的传递,在此过程中我们了解了进程是如何与Binder驱动交互的,以及binder调用过程中的会执行的方法等,我们对于Binder就有了一个全面的了解。在本文还简单介绍 了应用开发者如何使用Binder,有了这些基础,我们后面分析Android系统其他部分的代码就会更加容易了。当然关于Binder驱动的代码,BInder线程池的管理这两块还没有分析,读者感性确可以自行阅读,也可查看其他博主的文章。
如果你也对于Android系统源码感兴趣,欢迎与我交流。博文因为个人局限,也难免会出现差错,欢迎大家指正。