歡迎轉載,轉載請註明:http://blog.csdn.net/zhgxhuaa
一個Binder實例
我們Binder的學習將從下面的一個實例開始。根據Android文檔中的描述,創建一個Binder服務主要包括如下3步:
下面具體看一下在eclipse中是如何開發一個Binder應用的。
第一步:在工程目錄下定義aidl文件。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
package com.zxh.ipc; import com.zxh.ipc.PermissionInfo; interface ITestManager{ int checkPermission(String
permName, String pkgName); int checkUidPermission(String
permName, int uid); boolean addPermission(in
PermissionInfo info); void removePermission(String
name); boolean isProtectedBroadcast(String
actionName); } |
第二步:在定義aidl後,eclipse在工程目錄的gen目錄下會自動生成對應的接口,下面是有aidl自動生成的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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
|
package com.zxh.ipc; public interface ITestManager extends android.os.IInterface { /**
Local-side IPC implementation stub class. */ public static abstract class Stub extends android.os.Binder implements com.zxh.ipc.ITestManager { private static final java.lang.String
DESCRIPTOR = "com.zxh.ipc.ITestManager" ; /**
Construct the stub at attach it to the interface. */ public Stub() { this .attachInterface( this ,
DESCRIPTOR); } /** *
Cast an IBinder object into an com.zxh.ipc.ITestManager interface, generating a proxy if needed. */ public static com.zxh.ipc.ITestManager
asInterface(android.os.IBinder obj) { if ((obj
== null ))
{ return null ; } android.os.IInterface
iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin
!= null )
&& (iin instanceof com.zxh.ipc.ITestManager)))
{ return ((com.zxh.ipc.ITestManager)
iin); } return new com.zxh.ipc.ITestManager.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_checkPermission:
{ data.enforceInterface(DESCRIPTOR); java.lang.String
_arg0; _arg0
= data.readString(); java.lang.String
_arg1; _arg1
= data.readString(); int _result
= this .checkPermission(_arg0,
_arg1); reply.writeNoException(); reply.writeInt(_result); return true ; } case TRANSACTION_checkUidPermission:
{ data.enforceInterface(DESCRIPTOR); java.lang.String
_arg0; _arg0
= data.readString(); int _arg1; _arg1
= data.readInt(); int _result
= this .checkUidPermission(_arg0,
_arg1); reply.writeNoException(); reply.writeInt(_result); return true ; } case TRANSACTION_addPermission:
{ data.enforceInterface(DESCRIPTOR); com.zxh.ipc.PermissionInfo
_arg0; if (( 0 !=
data.readInt())) { _arg0
= com.zxh.ipc.PermissionInfo.CREATOR.createFromParcel(data); } else { _arg0
= null ; } boolean _result
= this .addPermission(_arg0); reply.writeNoException(); reply.writeInt(((_result)
? ( 1 )
: ( 0 ))); return true ; } case TRANSACTION_removePermission:
{ data.enforceInterface(DESCRIPTOR); java.lang.String
_arg0; _arg0
= data.readString(); this .removePermission(_arg0); reply.writeNoException(); return true ; } case TRANSACTION_isProtectedBroadcast:
{ data.enforceInterface(DESCRIPTOR); java.lang.String
_arg0; _arg0
= data.readString(); boolean _result
= this .isProtectedBroadcast(_arg0); reply.writeNoException(); reply.writeInt(((_result)
? ( 1 )
: ( 0 ))); return true ; } } return super .onTransact(code,
data, reply, flags); } private static class Proxy implements com.zxh.ipc.ITestManager { 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 int checkPermission(java.lang.String
permName, java.lang.String pkgName) throws android.os.RemoteException { android.os.Parcel
_data = android.os.Parcel.obtain(); android.os.Parcel
_reply = android.os.Parcel.obtain(); int _result; try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeString(permName); _data.writeString(pkgName); mRemote.transact(Stub.TRANSACTION_checkPermission,
_data, _reply, 0 ); _reply.readException(); _result
= _reply.readInt(); } finally { _reply.recycle(); _data.recycle(); } return _result; } @Override public int checkUidPermission(java.lang.String
permName, int uid) throws android.os.RemoteException { android.os.Parcel
_data = android.os.Parcel.obtain(); android.os.Parcel
_reply = android.os.Parcel.obtain(); int _result; try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeString(permName); _data.writeInt(uid); mRemote.transact(Stub.TRANSACTION_checkUidPermission,
_data, _reply, 0 ); _reply.readException(); _result
= _reply.readInt(); } finally { _reply.recycle(); _data.recycle(); } return _result; } @Override public boolean addPermission(com.zxh.ipc.PermissionInfo
info) throws android.os.RemoteException { android.os.Parcel
_data = android.os.Parcel.obtain(); android.os.Parcel
_reply = android.os.Parcel.obtain(); boolean _result; try { _data.writeInterfaceToken(DESCRIPTOR); if ((info
!= null ))
{ _data.writeInt( 1 ); info.writeToParcel(_data, 0 ); } else { _data.writeInt( 0 ); } mRemote.transact(Stub.TRANSACTION_addPermission,
_data, _reply, 0 ); _reply.readException(); _result
= ( 0 !=
_reply.readInt()); } finally { _reply.recycle(); _data.recycle(); } return _result; } @Override public void removePermission(java.lang.String
name) 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(name); mRemote.transact(Stub.TRANSACTION_removePermission,
_data, _reply, 0 ); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } @Override public boolean isProtectedBroadcast(java.lang.String
actionName) throws android.os.RemoteException { android.os.Parcel
_data = android.os.Parcel.obtain(); android.os.Parcel
_reply = android.os.Parcel.obtain(); boolean _result; try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeString(actionName); mRemote.transact(Stub.TRANSACTION_isProtectedBroadcast,
_data, _reply, 0 ); _reply.readException(); _result
= ( 0 !=
_reply.readInt()); } finally { _reply.recycle(); _data.recycle(); } return _result; } } static final int TRANSACTION_checkPermission
= (android.os.IBinder.FIRST_CALL_TRANSACTION + 0 ); static final int TRANSACTION_checkUidPermission
= (android.os.IBinder.FIRST_CALL_TRANSACTION + 1 ); static final int TRANSACTION_addPermission
= (android.os.IBinder.FIRST_CALL_TRANSACTION + 2 ); static final int TRANSACTION_removePermission
= (android.os.IBinder.FIRST_CALL_TRANSACTION + 3 ); static final int TRANSACTION_isProtectedBroadcast
= (android.os.IBinder.FIRST_CALL_TRANSACTION + 4 ); } public int checkPermission(java.lang.String
permName, java.lang.String pkgName) throws android.os.RemoteException; public int checkUidPermission(java.lang.String
permName, int uid) throws android.os.RemoteException; public boolean addPermission(com.zxh.ipc.PermissionInfo
info) throws android.os.RemoteException; public void removePermission(java.lang.String
name) throws android.os.RemoteException; public boolean isProtectedBroadcast(java.lang.String
actionName) throws android.os.RemoteException; } |
第三步:繼承上一步生成的接口,實現自己的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
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
|
package com.zxh.server; import android.app.Service; import android.content.Intent; import android.content.ServiceConnection; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; import com.zxh.ipc.ITestManager; import com.zxh.ipc.PermissionInfo; public class TestService extends Service{ private final static String
TAG = "zxh" ; class TestManagerService extends ITestManager.Stub{ @Override public int checkPermission(String
permName, String pkgName) throws RemoteException
{ Log.i(TAG, "checkPermission
server" ); return 0 ; } @Override public int checkUidPermission(String
permName, int uid) throws RemoteException
{ Log.i(TAG, "checkUidPermission
server" ); return 0 ; } @Override public boolean addPermission(PermissionInfo
info) throws RemoteException
{ Log.i(TAG, "addPermission
server" ); return false ; } @Override public void removePermission(String
name) throws RemoteException
{ Log.i(TAG, "removePermission
server" ); } @Override public boolean isProtectedBroadcast(String
actionName) throws RemoteException
{ Log.i(TAG, "isProtectedBroadcast
server" ); return false ; } } private TestManagerService
mService = new TestManagerService(); @Override public IBinder
onBind(Intent intent) { Log.i( "zxh" , "unbindService" ); return mService; } @Override public void unbindService(ServiceConnection
conn) { super .unbindService(conn); Log.i( "zxh" , "unbindService" ); } } |
第四步:實現客戶端代碼:
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
|
package com.zxh.server; import android.app.Activity; import android.app.Service; import android.content.ComponentName; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import com.zxh.ipc.ITestManager; public class MainActivity extends Activity
{ private ITestManager
manager = null ; ServiceConnection
connection = new ServiceConnection()
{ @Override public void onServiceDisconnected(ComponentName
name) { Log.i( "binder" , "onServiceDisconnected" ); } @Override public void onServiceConnected(ComponentName
name, IBinder service) { manager
= ITestManager.Stub.asInterface(service); } }; @Override protected void onCreate(Bundle
savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.activity_main); findViewById(R.id.startServer).setOnClickListener( new OnClickListener()
{ @Override public void onClick(View
v) { bindService( new Intent(MainActivity. this ,
TestService. class ),
connection, Service.BIND_AUTO_CREATE); } }); findViewById(R.id.stop).setOnClickListener( new OnClickListener()
{ @Override public void onClick(View
v) { unbindService(connection); } }); findViewById(R.id.check).setOnClickListener( new OnClickListener()
{ @Override public void onClick(View
v) { try { manager.checkPermission( "permName" , "pkgName" ); } catch (RemoteException
e) { e.printStackTrace(); } } }); } } |
到這裏我們就實現了一個完整的Binder實例,下面是工程目錄的截圖:
完整代碼可以查看後面的附件。下面來介紹一下這個實例中涉及到的一些知識點。
AIDL
除了eclipse,也可以使用Android開發包中提供的aidl命令工具來生成,如下是adil命令:
關於adil的詳細介紹可以查看Android官方文檔,地址爲:http://developer.android.com/intl/zh-cn/guide/components/aidl.html
想要了解aidl處理過程的朋友也可以自己查看aidl的源代碼,位於@/frameworks/base/tools/adil。
AIDL編譯產生的類
下面我們來分析一下aidl編譯產生的ITestManager類。
從ITestManager中可以看出,ITestManager實現了IInterface接口。在ITestManager類中共包含了三部分內容,分別是:
-
我們在ITestManager.adil中定義的接口。
-
Stub類:主要由Server端實現,Server端通過繼承本類,來提供具體的處理邏輯。
-
Proxy類:客戶端代理,通過mRemote成員變量訪問遠程Binder服務。
爲了實現我們在ITestManager自定義接口的跨進程通信,Stub類和Proxy都實現了ITestManager接口。Stub自己繼承了Binder類來實現Binder機制,Proxy則以引用的方式實現Binder機制。
客戶端和服務端的通信主要通過onTransact方法實現,客戶端和服務端的數據傳遞通過Parcel類完成。這裏需要注意一個問題:就是在客戶端寫入數據的順序與在服務端讀取數據的順序必須是一致的。
雖然在上面的實現中,我們定義了一個Service類TestService,但這裏要說明的是Service甚至adil都不是必須的,使用者完全可以自己定義。