一、今日学习内容
今日继续binder的学习
根据昨天学习的两个方法我们就可以实现Client和Server端的通信,接下来我们看看具体该怎么使用。 在Server接收到Client传来的消息(data)时,会对data进行验证data.enforceInterface(DESCRIPTOR),DESCRIPTOR是一个字符串类型的描述符,当data的描述符跟DESCRIPTOR相同时才能通过验证。
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
|
public class Stub extends Binder { //描述符 public static final java.lang.String DESCRIPTOR = "MyTestBinder" ; //code 方法描述符 public static final int TRANSACTION_test0 = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0 ); public static final int TRANSACTION_test1 = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1 ); @Override protected boolean onTransact( int code, Parcel data, Parcel reply, int flags) throws RemoteException { switch (code) { case TRANSACTION_test0: //验证描述符 data.enforceInterface(DESCRIPTOR); //执行方法 test0(); return true ; case TRANSACTION_test1: //验证描述符 data.enforceInterface(DESCRIPTOR); //执行方法 test1(data, reply); return true ; } return super .onTransact(code, data, reply, flags); } //无返回值 private void test0() { Log.d( "MyBinderServer" , "test0" ); } //有返回值 private void test1(Parcel data, Parcel reply) { Log.d( "MyBinderServer" , "test1" ); reply.writeInt(data.readInt() + 1 ); } } |
我们知道,要想实现Client和Server端的通信连接,就必须让client知道server端的地址,就跟Http请求,我们要知道服务端的ip和端口。Binder通信其实也是一样的,那么我们怎么让Client拿到Server的地址呢? 一种是跟Http请求一样,我们知道Http请求要把域名转换成ip和端口,这就是DNS,我们也需要一个Binder的DNS。安卓中也为我们提供了Binder的“DNS”那就是ServiceManager,ServiceManager中注册了所有系统服务(如MediaServer等),我们可以使用ServiceManager拿到远程的Binder地址,这种方式叫做有名Binder查找(有名Binder,如MediaServer等这些系统服务被注册的时候都是有名字的,比如,我们通过WINDOW_SERVICE这个名字就能拿到WindowManager)。但是问题是向ServiceManager注册服务的过程是系统进程实现的,我们的应用进程不能注册自己的Binder。 另一种就是利用有名的Binder来辅助传递匿名的Binder,也就是说如果有某个有名Binder服务它提供了传递Binder的方法,那么我们就可以通过这个Binder服务来传递我们的匿名Binder,我们查找到这个有名的Binder是不是就能拿到我们的匿名Binder。正好AMS其实提供了这样的功能,它通过Service.onBind把匿名的Binder封装在了Service里面供我们调用。
1
2
3
4
5
6
7
|
public class MyService extends Service { @Override public IBinder onBind(Intent intent) { return new Stub(); } } |
我们使用binderService()来获取远程的Binder。
1
2
3
4
5
6
7
8
9
10
11
12
|
Intent serviceIntent = new Intent( this , MyService. class ); bindService(serviceIntent, new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { //service可以理解为是远程Binder的地址,我们利用他跟远程通信,C++层会转换这个IBinder跟Binder进行通信 } @Override public void onServiceDisconnected(ComponentName name) { } }, BIND_AUTO_CREATE); |
获取到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
47
48
49
50
51
52
53
54
55
|
bindService(serviceIntent, new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { Parcel data0 = Parcel.obtain(); //请求参数 Parcel reply0 = Parcel.obtain(); //响应参数 Parcel data1 = Parcel.obtain(); Parcel reply1 = Parcel.obtain(); //调用第一个方法 try { //添加描述符 data0.writeInterfaceToken(Stub.DESCRIPTOR); /* * 写入参数,要想传递多个int参数,顺序调用writeInt * data0.writeInt(10); * data0.writeInt(20); * 获取 * int num10 = data0.readInt(); * int num20 = data0.readInt(); */ data0.writeInt( 10 ); //发起远程调用 service.transact(Stub.TRANSACTION_test0, data0, reply0, 0 ); reply0.readException(); } catch (RemoteException e) { e.printStackTrace(); } finally { data0.recycle(); reply0.recycle(); } //调用第二个方法 try { //添加描述符 data1.writeInterfaceToken(Stub.DESCRIPTOR); data1.writeInt( 10 ); //发起远程调用 service.transact(Stub.TRANSACTION_test1, data1, reply1, 0 ); reply1.readException(); //读取返回值 int num = reply1.readInt(); Log.d(TAG, "reply value: " + num); } catch (RemoteException e) { e.printStackTrace(); } finally { data1.recycle(); reply1.recycle(); } } @Override public void onServiceDisconnected(ComponentName name) { } }, BIND_AUTO_CREATE); |
为了方便调用,我们写一个代理类来封装通信过程
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
|
public class Proxy { //描述符 public static final java.lang.String DESCRIPTOR = "MyTestBinder" ; //code 方法描述符 public static final int TRANSACTION_test0 = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0 ); public static final int TRANSACTION_test1 = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1 ); private IBinder mRemote; public Proxy(IBinder remote) { this .mRemote = remote; } public void test1() { Parcel data0 = Parcel.obtain(); //请求参数 Parcel reply0 = Parcel.obtain(); //响应参数 //调用第一个方法 try { //添加描述符 data0.writeInterfaceToken(DESCRIPTOR); /* * 写入参数,要想传递多个int参数,顺序调用writeInt * data0.writeInt(10); * data0.writeInt(20); * 获取 * int num10 = data0.readInt(); * int num20 = data0.readInt(); */ data0.writeInt( 10 ); //发起远程调用 mRemote.transact(TRANSACTION_test0, data0, reply0, 0 ); reply0.readException(); } catch (RemoteException e) { e.printStackTrace(); } finally { data0.recycle(); reply0.recycle(); } } public int test2() { Parcel data1 = Parcel.obtain(); Parcel reply1 = Parcel.obtain(); //调用第二个方法 int num = 0 ; try { //添加描述符 data1.writeInterfaceToken(DESCRIPTOR); data1.writeInt( 10 ); //发起远程调用 mRemote.transact(TRANSACTION_test1, data1, reply1, 0 ); reply1.readException(); //读取返回值 num = reply1.readInt(); } catch (RemoteException e) { e.printStackTrace(); } finally { data1.recycle(); reply1.recycle(); } return num; } } |
1
2
3
4
5
6
7
8
9
10
11
12
13
|
bindService(serviceIntent, new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { Proxy proxy = new Proxy(service); proxy.test1(); int i = proxy.test2(); } @Override public void onServiceDisconnected(ComponentName name) { } }, BIND_AUTO_CREATE); |
二、遇到的问题
暂无
三、明日计划
继续binder的学习