自頂向下分析Binder【1】—— Binder實例篇

歡迎轉載,轉載請註明: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都不是必須的,使用者完全可以自己定義。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章