Android Binder Internals

use*_*376 5 android driver android-binder

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

有没有人对Binder系统有深入的了解,并且知道为什么Binder"阻止"转移包裹的过程,以及接收过程如何解除阻塞?

HFS*_*Dev 3

这是 Android 文档中所述的预期行为: http://developer.android.com/reference/android/os/IBinder.html

关键的 IBinder API 是与 Binder.onTransact() 相匹配的 transact()。这些方法允许您分别发送对 IBinder 对象的调用和接收对 Binder 对象的调用。该事务 API 是同步的,因此对 transact() 的调用不会返回,直到目标从 Binder.onTransact() 返回;这是调用本地进程中存在的对象时的预期行为,并且底层进程间通信 (IPC) 机制确保在跨进程时应用这些相同的语义。

观察通知 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    }
Run Code Online (Sandbox Code Playgroud)

此调用与您的进程同步,并将导致以下调用:

 @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}
Run Code Online (Sandbox Code Playgroud)

看到对 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}
Run Code Online (Sandbox Code Playgroud)

现在的方法(来自IBinder) mRemote.transact(Stub.TRANSACTION_enqueueNotification, _data, _reply, 0); 会发挥魔法的。根据 Parcel 类的文档:

Parcel 可以包含将在 IPC 的另一端展开的扁平化数据(使用此处的各种方法来编写特定类型或通用 Parcelable 接口),以及对活动 IBinder 对象的引用,这将导致另一端接收与 Parcel 中原始 IBinder 连接的代理 IBinder。

所以对方一旦收到序列化的数据,就会做出相应的响应。因此,由于系统设计,它会阻止调用过程,让开发更加连续,不增加应用程序开发的复杂性并保持一致性。接收进程不会被阻塞,它是一个活动的 IBinder 对象,并且它的线程之一将应答请求。现在,如果对象在繁重的开销下工作,它可能会在应答之前阻塞很长时间。因此,如果您打算与忙碌的人交谈,请确保您有一个助手来继续等待回复(也许是另一个线程)。

\o/