preface
IPC series of articles: Recommended reading in order.
Android IPC Service Android IPC AIDL Service Android IPC AIDL Android IPC server (IBinder) Android IPC server (IBinder)
After analyzing AIDL in detail from the source code +Demo point of view, this article will analyze the principle and application of AIDL simplified Messenger. Through this article, you will learn:
Messenger client sends a Message to the server. The server sends a Message to the client
1. The Messenger client sends a message to the server
Like AIDL, server-side and client-side logic is still written separately.
Write server
public class MyService extends Service { private String TAG = "ipc"; // create Handler, Private Handler Handler = new Handler(looper.getMainLooper ()) {@override public void handleMessage(@NonNull Message msg) { Bundle bundle = msg.getData(); int id = bundle.getInt("id"); Log.d(TAG, "receive id from client, id:" + id); }}; @override public IBinder onBind(Intent Intent) {return new Messenger(handler).getbinder (); }}Copy the code
Writing a client
ServiceConnection serviceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName Name, IBinder service) {// Use the IBinder reference to construct Messenger Messenger = new Messenger(service); // construct Message Message Message = message.obtain (); Bundle Bundle = new Bundle(); bundle.putInt("id", 100); message.setData(bundle); Try {// Send a message messenger.send(message); } catch (Exception e) { } } @Override public void onServiceDisconnected(ComponentName name) { } }; private void bindService() { Intent intent = new Intent(MainActivity.this, MyService.class); bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE); }Copy the code
The process is as follows:
1, The server constructs a Handler to receive messages. 2, the client constructs a Messenger to send messages
The server receives the message and prints the following:
You can see how convenient it is to communicate between processes without writing any AIDL files.
2. The Messenger server sends messages to the client
In the Demo above, the client sends a message to the server. What if the server wants to send a reply message to the client? For example, after receiving the ID from the client, the server finds out the name and age of the student corresponding to the ID and sends it to the client.
Write server
Modify the server code:
// create Handler, Private Handler Handler = new Handler(looper.getMainLooper ()) {@override public void handleMessage(@NonNull Message msg) { Bundle bundle = msg.getData(); int id = bundle.getInt("id"); Log.d(TAG, "receive id from client, id:" + id); Msg. replyTo = msg.replyTo; msg.replyTo = msg.replyTo; if (replyMessenger ! = null) {Message = message.obtain (); Bundle replyBundle = new Bundle(); replyBundle.putString("name", "xiaoming"); replyBundle.putInt("age", 18); message.setData(replyBundle); try { replyMessenger.send(message); } catch (Exception e) { } } } };Copy the code
Just modify the handleMessage(xx), when receiving the message from the client immediately return the name and age of the query sent to the client.
Writing a client
The client code also requires only minor changes:
Private Handler Handler = new Handler(looper.getMainLooper ()) {@override public void handleMessage(@nonnull) Message msg) { Bundle bundle = msg.getData(); if (bundle ! String name = bundle.getString("name"); int age = bundle.getInt("age"); Log.d("ipc", "receive name, age from server, name:" + name + "age:" + age); }}}; ServiceConnection serviceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName Name, IBinder service) {// Use the IBinder reference to construct Messenger Messenger = new Messenger(service); // construct Message Message Message = message.obtain (); Bundle Bundle = new Bundle(); bundle.putInt("id", 100); message.setData(bundle); ReplyTo = new Messenger(handler); Try {// Send a message messenger.send(message); } catch (Exception e) { } } @Override public void onServiceDisconnected(ComponentName name) { } };Copy the code
When a client sends a message to a server, it carries its own Messenger so that the server can retrieve the Messenger to send messages to the client. At the same time, the handleMessage(xx) of the Handler needs to be overridden to receive information from the server. This is consistent with the server-side implementation, which is equivalent to having Messenger on both sides.
At this point, with the help of Messenger, client/server communication is easily accomplished.
3. Basic principles of Messenger
Start by sending a message
Find out why Messenger can do IPC so easily, starting with sending messages.
#Messenger.java
public void send(Message message) throws RemoteException {
mTarget.send(message);
}
Copy the code
The mTarget is of type IMessenger and is initialized in the Messenger constructor:
#Messenger.java
public Messenger(Handler target) {
mTarget = target.getIMessenger();
}
Copy the code
If target is of type Handler, go to Handler.
#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(); // call Handler to sendMessage handler.this. sendMessage(MSG); }}Copy the code
To see if this is similar, MessengerImpl inherits from IMessenger.Stub and implements a single method: send(Message MSG), which takes Message. From this, we can easily draw the conclusion that:
1. The server exposes the IMessenger interface, which has a unique method: Send (Message MSG). 2. The server implements the send(Message MSG) method, which sends messages using the Handler.
Find the AIDL file for IMessenger:
package android.os;
import android.os.Message;
/** @hide */
oneway interface IMessenger {
void send(in Message msg);
}
Copy the code
Note: this document in the framework/core/Java/android/OS/IMessenger aidl aidl is said before, the Message itself to support serialization, add “in” tag data can only flow from the client to the server.
The interface definition has an additional identifier: “oneway”. This field will eventually affect the last parameter in ibinder.transact (xx) :
boolean _status = mRemote.transact(Stub.TRANSACTION_send,
_data, null, android.os.IBinder.FLAG_ONEWAY);
Copy the code
FLAG_ONEWAY indicates that transact(xx) is not a blocking call, meaning that the client calls the method immediately and returns without waiting. If you think about it, you don’t need to wait, because send(xx) returns no value and the in modifier parameter, and data flows can’t flow from the server to the client.
Why can a server send messages to a client
From the IMessenger. Aidl definition, the send(xx) method can only send messages from the client to the server, and no value is returned. Therefore, it is not practical to carry server data through method parameters or return values. The biggest proof that a client can send data to a server is that the client can access the IBinder interface of the server. So how about the other way around? Let’s look at the fields in message.java:
#Message.java /** * Optional Messenger where replies to this message can be sent. The * semantics of exactly how this is used are up to the sender and * receiver. */ public Messenger replyTo;Copy the code
Message can hold a Messenger reference, and we know that once Messenger is constructed, we can get the associated IBinder reference through getBinder(xx).
#Messenger.java
public IBinder getBinder() {
return mTarget.asBinder();
}
Copy the code
The IBinder has it and all that’s left is to figure out how to pass it to the server.
Client delivery of IBinder to server Message is cross-process, so its member variables, including Messenger replyTo, need to be serialized and deserialized.
#Message.java public void writeToParcel(Parcel dest, int flags) { ... Messenger.writeMessengerOrNullToParcel(replyTo, dest); . }Copy the code
Static method called in Messenger:
#Messenger.java public static void writeMessengerOrNullToParcel(Messenger messenger, Parcel out) {// Get the Binder associated with Messenger and write it to the serialized object out.writeStrongBinder(Messenger! = null ? messenger.mTarget.asBinder() : null); }Copy the code
At this point, the client IBinder reference can be passed to the server.
After receiving the Message, the server deserializes member variables such as Messenger replyTo.
#Message.java private void readFromParcel(Parcel source) { ... replyTo = Messenger.readMessengerOrNullFromParcel(source); . }Copy the code
Similar calls to Messenger static methods:
# Messenger. Java public static Messenger readMessengerOrNullFromParcel (Parcel in) {/ / deserialize the IBinder IBinder = b in.readStrongBinder(); Messenger return b! = null ? new Messenger(b) : null; }Copy the code
Eventually, the server receives the IBinder from the client and constructs Messenger, which of course can send messages to the client.
4. Message, AIDL, Messenger
Message is used to pass data between threads. Used in conjunction with handlers, it supports serialization itself and can pass Message objects across processes. AIDL is used to simplify client-side and server-side code writing for interprocess communication. On the basis of AIDL, Messenger further encapsulates the interface exposed by the server and sends the Message received by the server to the target thread through the handler.
Use AIDL to communicate with Messenger.
1, can flexibly write server-side interface, and can customize method parameter type, data flow, method return value. 2, server-side method implementation can open multi-threaded data processing.
Disadvantages of using AIDL:
1. You need to write an AIDL file to define the server interface. 2, if it is a custom data type, also need to write the corresponding AIDL file.
Advantages of using Messenger:
1. Construct Message without defining AIDL file. 2. Fast bidirectional communication (technically AIDL can do this, but Messenger encapsulates IBinder delivery)
Disadvantages of using Messenger:
See above, AIDL’s strengths are Messenger’s weaknesses.
Applicable occasions
Messenger is recommended for simple communications where the server processes messages from the client in a single-threaded order.
This article is based on Android 10.0.