背景
这几天在学习安卓的进程间通信方式,方学AIDL,又看Messenger。
Messenger可以和Handler结合,从而使IPC就像线程间通信一样
而Messenger的实现原理,其实也是用的AIDL,如果对AIDL不甚熟悉,可以参见我的文章安卓开发学习之AIDL的使用
使用步骤
1、在服务端建立Service
内部构造一个messenger,做为接收客户端来信的信使,代码如下
public class MessengerService extends Service { private Messenger messenger = new Messenger(new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case 0: try { Bundle content = (Bundle) msg.obj; String info = content.getString("info", "nothing"); System.out.println(info); Message replyMesg = Message.obtain(); replyMesg.what = 0; content.clear(); content.putString("info", "Got it,service pid:" + Process.myPid()); replyMesg.obj = content; msg.replyTo.send(replyMesg); // replyTo也是一个Messenger } catch (Exception e) { e.printStackTrace(); } break; } } }); @Override public IBinder onBind(Intent intent) { return messenger.getBinder(); // 一会儿将看到,getBinder()返回的是一个Stub对象 } }
在清单文件中注册,把name填成:remote,让service做为新的进程,代码如下
<service android:name=".MessengerService" android:exported="true" android:process=":remote"> <intent-filter> <action android:name="com.example.songzeceng.Messenger"></action> <category android:name="android.intent.category.DEFAULT"/> </intent-filter> </service>
2、客户端建立连接
建立两个Messenger,ServiceMessenger用来向服务端发送数据,ClientMessenger用来从服务端接收数据,代码如下
public class MainActivity extends Activity { public static final String TAG = "MainActivity"; private boolean isConnected = false; private Messenger serviceMessenger; private Messenger clientMessenger = new Messenger(new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case 0: Bundle content = (Bundle) msg.obj; String info = content.getString("info", "nothing"); logger(info); break; } } }); private ServiceConnection connection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { try { System.out.println(service.getClass().getCanonicalName()); serviceMessenger = new Messenger(service); // 此时ServiceMessenger内部负责传递的则是Proxy类 Message msg = Message.obtain(); msg.what = 0; // msg.obj = "客户端来信,pid:" + Process.myPid(); // IPC时传递的数据类型必须实现Parcelable接口,然而String没有实现 Bundle bundle = new Bundle(); bundle.putString("info", "客户端来信,pid:" + Process.myPid()); msg.obj = bundle; msg.replyTo = clientMessenger; serviceMessenger.send(msg); isConnected = true; } catch (Exception e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { isConnected = false; } }; private void logger(String s) { Log.i(TAG, s); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override protected void onStart() { super.onStart(); if (!isConnected) { Intent intent = new Intent(this, MessengerService.class); intent.setAction("com.example.songzeceng.Messenger"); bindService(intent, connection, BIND_AUTO_CREATE); } } @Override protected void onStop() { super.onStop(); if (isConnected) { unbindService(connection); isConnected = false; } } }
运行结果
服务端截图
客户端截图
可见,实现了进程间的通信
源码分析
1、服务端
从服务端开始,进行源码分析
我们先是构造了一个Messenger对象,给构造方法传入一个Handler对象,Messenger的这个构造方法代码如下
public Messenger(Handler target) { mTarget = target.getIMessenger(); }
mTarget是IMessenger类型的,这个IMessenger就是用aidl生成的接口类,而后面调用了Handler的getIMessenger()方法,这个方法源码如下
final IMessenger getIMessenger() { synchronized (mQueue) { if (mMessenger != null) { return mMessenger; } mMessenger = new MessengerImpl(); return mMessenger; } }
返回的是一个MessengerImpl对象,MessengerImpl是Handler的内部类,源码如下
private final class MessengerImpl extends IMessenger.Stub { public void send(Message msg) { msg.sendingUid = Binder.getCallingUid(); Handler.this.sendMessage(msg); } }
相当于IMessenger.Stub对象,这似乎也是Stub的唯一子类,所以我也认为Stub的send()方法就是最终调用了handler的sendMessage()方法
好,返回Messenger的构造方法,服务端的Messenger里的mTarget就是一个MessengerImpl对象,也是一个Stub对象
之后客户端连接service,服务端调用onBind(),代码如下
@Override public IBinder onBind(Intent intent) { return messenger.getBinder(); }
调用了messenger.getBinder(),此方法代码如下
public IBinder getBinder() { return mTarget.asBinder(); }
调用的是mTarget.asBinder(),我方才说过,mTarget是一个IMessenger.Stub,这个类的源码如下
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); } /** * Cast an IBinder object into an android.os.IMessenger interface, * generating a proxy if needed. */ public static android.os.IMessenger asInterface(android.os.IBinder obj) { if ((obj == null)) { return null; } android.os.IInterface iin = (android.os.IInterface) obj .queryLocalInterface(DESCRIPTOR); if (((iin != null) && (iin instanceof android.os.IMessenger))) { return ((android.os.IMessenger) iin); } return new android.os.IMessenger.Stub.Proxy(obj); } 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_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); } static final int TRANSACTION_send = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); } public void send(android.os.Message msg) throws android.os.RemoteException; }
asBinder()方法返回的是Stub自己,所以messenger.getBinder()方法,返回的是handler里面的IMessengerImpl对象,也就是Stub对象
2、客户端
客户端直接看onServiceConnected()里的内容,上来根据服务端onBind()方法返回的IBinder对象,构造serviceMessenger,这个构造方法代码如下
public Messenger(IBinder target) { mTarget = IMessenger.Stub.asInterface(target); }
翻翻上面的Stub的asInterface()方法,会发现如果客户端本地没有IMessenger接口对象,就返回Proxy对象,而Proxy对象里的mRemote,就是服务端返回的IBinder,也就是一个Stub;但如果已经有了IMessenger实现类对象,就返回那个对象
现在,虽然之前在客户端我们实例化了一个ClientMessenger,但它里面的handler的IMessengerImpl和服务端返回的IMessengerImpl是两个对象,所以asInterface()还是返回的是Proxy对象
通过反射获取serviceMessenger.mTarget类型的结果如下
所以当我们通过serviceMessenger发送消息时,调用的是Proxy的send()方法,通过clientMessenger接收消息时,调用的是Stub的send()方法
Proxy的源码如下
private static class Proxy implements android.os.IMessenger { private android.os.IBinder mRemote; Proxy(android.os.IBinder remote) { mRemote = remote; } public android.os.IBinder asBinder() { return mRemote; } public java.lang.String getInterfaceDescriptor() { return DESCRIPTOR; } 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); // Message实现了Parcelable接口 } else { _data.writeInt(0); } mRemote.transact(Stub.TRANSACTION_send, _data, null, android.os.IBinder.FLAG_ONEWAY); } finally { _data.recycle(); } } }所以,综上所述,serviceMessenger.send()调用的是Proxy.send(),然后经过onTransact调用的是Service端的messenger.handler.IMessengerImpl.send()方法;服务端的message.reply.send()则是调用了客户端clientMessenger.handler.IMessengerImpl.send()方法。本质都是Stub在发送,都是AIDL的封装