In the previous article (service usage), we introduced the use of Android inter-process communication (IPC) and provided an example. However, we have not thoroughly analyzed how aidl can implement inter-process communication and how it executes?
This article analyzes the execution process of iremoteservice. aidl and understands how aidl communicates across processes.
When we create the iremoteservice. aidl file, IDE will create the corresponding file for us in the gen directory.
/** This file is auto-generated. do not modify. * Original file: F :\\ workspace \ androidimprove \ SRC \ com \ example \ aidl \ iremoteservice. aidl */package COM. example. aidl; public interface iremoteservice extends android. OS. iinterface {/** local-side IPC implementation stub class. */public static abstract class stub extends android. OS. binder implements COM. example. aidl. iremoteservice {private stati C Final Java. lang. string descriptor = "com. example. aidl. iremoteservice ";/** construct the stub at attach it to the interface. */Public stub () {This. attachinterface (this, descriptor);}/*** cast an ibinder object into an COM. example. aidl. iremoteservice interface, * generating a proxy if needed. */public static COM. example. aidl. iremoteservice asinterface (Android. OS. ibinder OBJ) {If (OBJ = NUL L) {return NULL;} Android. OS. iinterface Iin = (Android. OS. iinterface) obj. querylocalinterface (descriptor); If (IIN! = NULL) & (IIN instanceof COM. example. aidl. iremoteservice) {return (COM. example. aidl. iremoteservice) iIn);} return new COM. example. aidl. iremoteservice. 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_tr Ansaction: {reply. writestring (descriptor); Return true;} case transaction_register: {data. enforceinterface (descriptor); COM. example. aidl. iremotecallback _ arg0; _ arg0 = com. example. aidl. iremotecallback. stub. asinterface (data. readstrongbinder (); this. register (_ arg0); reply. writenoexception (); Return true;} case transaction_unregister: {data. enforceinterface (descriptor); COM. example. aidl. iremote Callback _ arg0; _ arg0 = com. example. aidl. iremotecallback. stub. asinterface (data. readstrongbinder (); this. unregister (_ arg0); reply. writenoexception (); Return true;} case transaction_execute: {data. enforceinterface (descriptor); this.exe cute (); reply. writenoexception (); Return true;} case transaction_getstatus: {data. enforceinterface (descriptor); Java. lang. string _ arg0; _ arg0 = data. readstring (); Int _ result = This. getstatus (_ arg0); reply. writenoexception (); reply. writeint (_ result); Return true ;}} return Super. ontransact (Code, Data, reply, flags);} Private Static class proxy implements COM. example. aidl. iremoteservice {private android. OS. ibinder mremote; proxy (Android. OS. ibinder remote) {mremote = remote;} public android. OS. ibinder asbinder () {return mremote;} public Java. lang. stri Ng getinterfacedescriptor () {return descriptor;} // registers the callback public void register (COM. example. aidl. iremotecallback callback) throws android. OS. remoteException {android. OS. parcel _ DATA = android. OS. parcel. obtain (); android. OS. parcel _ reply = android. OS. parcel. obtain (); try {_ data. writeinterfacetoken (descriptor); _ data. writestrongbinder (callback! = NULL ))? (Callback. asbinder () :( null); mremote. transAct (stub. transaction_register, _ data, _ reply, 0); _ reply. readexception ();} finally {_ reply. recycle (); _ data. recycle () ;}}// cancel registration callback public void unregister (COM. example. aidl. iremotecallback callback) throws android. OS. remoteException {android. OS. parcel _ DATA = android. OS. parcel. obtain (); android. OS. parcel _ reply = android. OS. parcel. obtain (); try {_ DATA. Writeinterfacetoken (descriptor); _ data. writestrongbinder (callback! = NULL ))? (Callback. asbinder () :( null); mremote. transAct (stub. transaction_unregister, _ data, _ reply, 0); _ reply. readexception ();} finally {_ reply. recycle (); _ data. recycle () ;}}// execution callback public void execute () throws android. OS. remoteException {android. OS. parcel _ DATA = android. OS. parcel. obtain (); android. OS. parcel _ reply = android. OS. parcel. obtain (); try {_ data. writeinterfacetoken (descriptor); mremote. transAct (stub. transaction_execute, _ data, _ reply, 0); _ reply. readexception ();} finally {_ reply. recycle (); _ data. recycle () ;}// get the public int getstatus (Java. lang. string flag) throws android. OS. remoteException {android. OS. parcel _ DATA = android. OS. parcel. obtain (); android. OS. parcel _ reply = android. OS. parcel. obtain (); int _ result; try {_ data. writeinterfacetoken (descriptor); _ data. writestring (FLAG); mremote. transAct (stub. transaction_getstatus, _ data, _ reply, 0); _ reply. readexception (); _ result = _ reply. readint ();} finally {_ reply. recycle (); _ data. recycle ();} return _ result;} static final int transaction_register = (Android. OS. ibinder. first_call_transaction + 0); static final int transaction_unregister = (Android. OS. ibinder. first_call_transaction + 1); static final int transaction_execute = (Android. OS. ibinder. first_call_transaction + 2); static final int transaction_getstatus = (Android. OS. ibinder. first_call_transaction + 3);} // registration callback public void register (COM. example. aidl. iremotecallback callback) throws android. OS. remoteException; // cancel registration callback public void unregister (COM. example. aidl. iremotecallback callback) throws android. OS. remoteException; // execution callback public void execute () throws android. OS. remoteException; // get the public int getstatus (Java. lang. string flag) throws android. OS. remoteException ;}
When a clientactivity is bound to a remote service and a connection is established, serviceconnection. onserviceconnected (componentname, ibinder service) is called)
Public void onserviceconnected (componentname name, ibinder Service) {remoteservice = iremoteservice. stub. asinterface (service); // register the callback try {remoteservice. register (remotecallback);} catch (RemoteException e) {e. printstacktrace ();}}
The ibinder service is the iremoteservice. Stub ibinder returned from the remoteservice. This object is an object in the server application process.
Iremoteservice. stub. asinterface (service) creates a local proxy
Public static com. example. aidl. iremoteservice asinterface (Android. OS. ibinder OBJ)
{
If (OBJ = NULL )){
Return NULL;
}
Android. OS. iinterface Iin = (Android. OS. iinterface) obj. querylocalinterface (descriptor); // null is definitely returned here
If (IIN! = NULL) & (IIN instanceof com. example. aidl. iremoteservice ))){
Return (COM. example. aidl. iremoteservice) iIn );
}
Return new COM. example. aidl. iremoteservice. stub. Proxy (OBJ); // create a local proxy
}
When remoteservice is used to call a method, the local com. example. aidl. iremoteservice. stub. proxy object method. From the proxy method, we can see that each method executes mremote. transAct (stub. transaction_xxx, _ data, _ reply, 0 );.
For example:
// Obtain the public int getstatus (Java. lang. string flag) throws android. OS. remoteException {android. OS. parcel _ DATA = android. OS. parcel. obtain (); android. OS. parcel _ reply = android. OS. parcel. obtain (); int _ result; try {_ data. writeinterfacetoken (descriptor); _ data. writestring (FLAG); mremote. transAct (stub. transaction_getstatus, _ data, _ reply, 0); _ reply. readexception (); _ result = _ reply. readint ();} finally {_ reply. recycle (); _ data. recycle ();} return _ result ;}
In this process, the client parameters are converted to parcel (_ data) and passed to the server, while the server saves the returned data to _ reply, this forms an interaction.
Mremote is a remote object. The transact method executes the ontransact method.
public final boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { if (Config.LOGV) Log.v("Binder", "Transact: " + code + " to " + this); if (data != null) { data.setDataPosition(0); } boolean r = onTransact(code, data, reply, flags); if (reply != null) { reply.setDataPosition(0); } return r; }
In this way, the remote ontransact method will be executed,
case TRANSACTION_getStatus: { data.enforceInterface(DESCRIPTOR); java.lang.String _arg0; _arg0 = data.readString(); int _result = this.getStatus(_arg0); reply.writeNoException(); reply.writeInt(_result); return true; }
Note int _ result = This. getstatus (_ arg0);, this calls the getstatus (string flag) on the server side, and writes the returned results to the _ Reply of the proxy object on the client side.
At this point, the aidl communication process is complete.
PS: aidl communication is a bit complicated, but it is not difficult to analyze it carefully.