Android Binder Internals

时间:2012-09-20 09:07:34

标签: android driver android-binder

我正在开发一个项目,我们在android系统中添加了一些非标准的安全功能,而且我有一些严重的问题需要调整Binder。

有没有人对Binder系统有深入的了解,并知道Binder为什么会“阻止”传输包裹的过程,以及接收过程如何解除阻止?

2 个答案:

答案 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生成的代码能够从游泳池中拿出一块包裹,完成后再回收。