Android IPC之Messenger分析3

117 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第7天,点击查看活动详情

Messenger内部同时提供了服务端和客户端对应的方法,getBinder()是通过mTarget来返回的,mTarget是通过Handler的getIMessenger()来返回的,具体实现是在Handler内部,一起看一下Handler的内部对应的实现:

b.Handler.java
    final IMessenger getIMessenger() {
        synchronized (mQueue) {
            if (mMessenger != null) {
                return mMessenger;
            }
            mMessenger = new MessengerImpl();
            return mMessenger;
        }
    }

    private final class MessengerImpl extends IMessenger.Stub {
        public void send(Message msg) {
            msg.sendingUid = Binder.getCallingUid();
            Handler.this.sendMessage(msg);
        }
    }
c.IMessenger.aidl
oneway interface IMessenger {
    void send(in Message msg);
}
d.IMessenger.java
public interface IMessenger extends android.os.IInterface {
    /** Local-side IPC implementation stub class. */
    public static abstract class Stub extends android.os.Binder implements android.os.IMessenger {
        private static final java.lang.String DESCRIPTOR = "android.os.IMessenger";
        /** Construct the stub at attach it to the interface. */
        public Stub() {
            this.attachInterface(this, DESCRIPTOR);
        }
        ........
        ........
        @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 TRANSACTION_send: {
                    data.enforceInterface(DESCRIPTOR);
                    android.os.Message _arg0;
                    if ((0!=data.readInt())) {
                        _arg0 = android.os.Message.CREATOR.createFromParcel(data);
                    } else {
                        _arg0 = null;
                    }
                    this.send(_arg0);
                    return true;
                }
         }
         return super.onTransact(code, data, reply, flags);
    }

    private static class Proxy implements android.os.IMessenger {
        private android.os.IBinder mRemote;
        Proxy(android.os.IBinder remote) {
            mRemote = remote;
        }
        @Override public android.os.IBinder asBinder() {
            return mRemote;
        }
        .........
       @Override public void send(android.os.Message msg) throws android.os.RemoteException {
            android.os.Parcel _data = android.os.Parcel.obtain();
            try {
                _data.writeInterfaceToken(DESCRIPTOR);
               if ((msg!=null)) {
                   _data.writeInt(1);
                   msg.writeToParcel(_data, 0);
               } else {
                   _data.writeInt(0);
               }
                mRemote.transact(Stub.TRANSACTION_send, _data, null, android.os.IBinder.FLAG_ONEWAY);
             } finally {
                 _data.recycle();
             }
        }
    }
        static final int TRANSACTION_send = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    }
    public void send(android.os.Message msg) throws android.os.RemoteException;
}

       从上面可以看到,getIMessenger()返回的是MessengerImpl实例,而MessengerImpl是继承了IMessenger.Stub,实现了send()方法来接收消息,从这里可以看到,用的是跟AIDL相同的处理;

总结一下

服务端:service的onBind()方法调用Messenger.getBinder(),最终是通过IMessenger.Stub的asBinder()返回的IBinder;

客户端:onServiceConnected()里面调用Messenger mService=new Messenger(service)来返回Messenger对象,在构造方法内部会先通过IMessenger.Stub.asInterface(target)来创建IMessenger实例mTarget;

交互:客户端在通过send()发送消息时,会通过mTarget的send()方法,经过binder驱动处理,会调用到IMessenger.Stub的onTransact()方法,最终会调用服务端的MessengerImpl的send()方法,继而通过Handler来sendMessage(),最后服务端的Handler来handleMessage();

四.与 AIDL 比较:

执行 IPC 时,使用 Messenger 要比使用 AIDL 实现更加简单,因为 Messenger 会将所有服务调用排入队列,而纯粹的 AIDL 接口会同时向服务发送多个请求,服务随后必须应对多线程处理。

对于大多数应用,服务不需要执行多线程处理,因此使用 Messenger 可让服务一次处理一个调用。如果服务必须执行多线程处理,则应使用 AIDL 来定义接口。