我正在开发一个项目,我们在android系统中添加了一些非标准的安全功能,而且我有一些严重的问题需要调整Binder。
有没有人对Binder系统有深入的了解,并知道Binder为什么会“阻止”传输包裹的过程,以及接收过程如何解除阻止?
答案 0 :(得分:2)
这是Android文档中所说的预期行为: http://developer.android.com/reference/android/os/IBinder.html
关键的IBinder API是由Binder.onTransact()匹配的transact()。 这些方法允许您发送对IBinder对象的调用 接收分别进入Binder对象的呼叫。这个 事务API是同步的,这样调用transact()就可以了 直到目标从Binder.onTransact()返回后才返回; 这是调用存在的对象时的预期行为 本地进程和底层进程间通信 (IPC)机制确保在进行时适用这些相同的语义 跨进程。
观察Notification API。我们进行一些调用,以便最终获得对NotificationManager对象的引用。使用此对象,我们调用notify(...);
117 public void notify(String tag, int id, Notification notification)
118 {
119 int[] idOut = new int[1];
120 INotificationManager service = getService();
121 String pkg = mContext.getPackageName();
122 if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");
123 try {
124 service.enqueueNotificationWithTag(pkg, tag, id, notification, idOut);
125 if (id != idOut[0]) {
126 Log.w(TAG, "notify: id corrupted: sent " + id + ", got back " + idOut[0]);
127 }
128 } catch (RemoteException e) {
129 }
130 }
此调用与您的流程同步,将导致以下调用:
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
38 {
39 switch (code)
40 {
...
46 case TRANSACTION_enqueueNotification:
47 {
48 data.enforceInterface(DESCRIPTOR);
49 java.lang.String _arg0;
50 _arg0 = data.readString();
51 int _arg1;
52 _arg1 = data.readInt();
53 android.app.Notification _arg2;
54 if ((0!=data.readInt())) {
55 _arg2 = android.app.Notification.CREATOR.createFromParcel(data);
56 }
57 else {
58 _arg2 = null;
59 }
60 int[] _arg3;
61 _arg3 = data.createIntArray();
62 this.enqueueNotification(_arg0, _arg1, _arg2, _arg3);
63 reply.writeNoException();
64 reply.writeIntArray(_arg3);
65 return true;
66 }
67 case TRANSACTION_cancelNotification:
68 {
...
169return super.onTransact(code, data, reply, flags);
170}
请参阅this.enqueueNotification的调用?
public void enqueueNotification(java.lang.String pkg, int id, android.app.Notification notification, int[] idReceived) throws android.os.RemoteException
188{
189android.os.Parcel _data = android.os.Parcel.obtain();
190android.os.Parcel _reply = android.os.Parcel.obtain();
191try {
192_data.writeInterfaceToken(DESCRIPTOR);
193_data.writeString(pkg);
194_data.writeInt(id);
195if ((notification!=null)) {
196_data.writeInt(1);
197notification.writeToParcel(_data, 0);
198}
199else {
200_data.writeInt(0);
201}
202_data.writeIntArray(idReceived);
203mRemote.transact(Stub.TRANSACTION_enqueueNotification, _data, _reply, 0);
204_reply.readException();
205_reply.readIntArray(idReceived);
206}
207finally {
208_reply.recycle();
209_data.recycle();
210}
211}
现在的方法(来自IBinder)mRemote.transact(Stub.TRANSACTION_enqueueNotification,_data,_reply,0);会做神奇的事。根据Parcel类的文档:
包裹可以包含两个未展平的展平数据 IPC的另一面(使用此处的各种方法进行编写 特定类型,或一般的Parcelable接口)和引用 生活IBinder对象将导致另一方接收 代理IBinder与包裹中的原始IBinder连接。
因此,一旦另一方收到序列化数据,它将作出相应的响应。因此,它会因为系统设计而阻止调用过程,让开发更加连续,不会增加应用程序开发的复杂性和一致性。 接收过程未被阻止,它是一个实时IBinder对象,其中一个线程将回答该请求。现在,如果对象在繁重的开销下工作,它可能会在回答之前阻塞很长时间。因此,如果你打算与忙碌的人交谈,请确保你有一个助手等待响应(另一个线程,pehaps)。
\ O /
答案 1 :(得分:0)
阻塞和解除阻塞的确是设计使然-Binder是“基于事务的”,但实际上发生在IPCThreadState的较低级别,IPCThreadState是保存Binder数据的每个线程实例:
通过低级驱动程序(通常为/ dev / binder,但从8.0 vndbinder开始,从hwbinder开始)上的ioctl(2)操作发送/接收消息。这样一来,呼叫者就可以通过一种逻辑操作既可以发送消息也可以接收答复,而不是像套接字那样执行两个系统调用(send(2)/ receive(2))。
您的应用程序具有绑定程序线程池(由ProcessState启动),Android服务(尤其是system_server)也是如此。这就是服务来自驱动程序的传入事务和BR_ *代码的方法,这就是Binder看似“异步”的性质的发生方式-池处于休眠状态,但是当传入通知(例如BR_DEAD_BINDER)到达时,其中一个线程(您可以't控制哪个)在该线程中转换为Java回调(用于死亡通知onBinderDied)。
这种设计使您可以轻松享受两全其美的体验-在需要时看似异步操作,并在想要提交“事务”时阻止发送/接收,这也有助于AIDL生成的代码能够从游泳池中拿出一块包裹,完成后再回收。