This document is translated from Android official documentation, combined with your own tests, organized as follows.
Android Interface definition Language (aidl) allows us to define our own programming interface that enables cross-process communication between the client and service (interprocess communication, IPC). Typically, you cannot communicate directly across processes in Android. Therefore, it is necessary to decompose the passed objects into the original state (data) that the system can recognize and serialize them across processes marshalling. Because the marshalling process is cumbersome, Android is handled by Aidl.
Note: Aidl is required only when we allow clients of different applications to obtain the service for IPC, and when multi-threading is required in the service. The vast majority of applications should not use Aidl to create bound Service, as this may require multi-threading capabilities and will make the code more complex. Therefore, Aidl is not applicable to most applications. This is the most common way to interact directly with the binder class if it is used internally within the application and does not require cross-process. If you cross-process IPC and do not need to deal with multithreading issues, you can use the Messenger method because Messenger puts all the requests in one thread, so you don't have to worry about thread-safety issues.
(There are some problems with the following understanding) before you begin to design the Aidl interface, it is important to note that calling the Aidl interface is a direct calling method, and we should not assume that the calling method occurs on a child thread. The calls from the local process and the threads in the remote process are different:
- Called in the local process. If called in the main thread, the Aidl interface executes in the main thread. If another child thread, the thread executes the code in the service. So if only the local thread gets the service, we can take full control. This situation should not use aidl, but rather inherit the binder implementation.
- If the remote process is called, then the implementation of AIDL must ensure that the complete ground thread is secure. This is because if remote invocation is supported, it may be necessary to process multiple calls simultaneously (concurrent processing).
- One-way changes the remote invocation behavior. When this method is used, the remote call does not block; it simply sends the data and returns immediately. Eventually, the interface implementation receives the same remoting call as the regular call through the binder thread pool. If the one-way use is called locally, it will not be affected and the call is still asynchronous.
If you understand some of the above, we need to review the information and verify it, and please advise me.
Defining the Aidl interface
The Aidl interface must be defined in a .aidl
file (named to satisfy the Java syntax), and stored in the application where the service resides and other applications that bind the service (requires a service through AIDL for IPC), where the save location is in src/
source code Directory.
When we create a new .aidl
file, the Android SDK tool automatically generates a IBinder interface based on that file and is saved in the gen/
directory. The service must implement the IBinder interface so that the client can bind the service and invoke the method to obtain the object for IPC.
The above directory is in Eclipse, in Android Studio:
To be able to create a service that uses AIDL, you must implement the following steps:
- Create a
.aidl
file
The file defines the programming interface with the method declaration
- Implementing interfaces
The Android SDK tool uses Java to generate an interface based on the .aidl
file. There is an internal abstract class stub in this interface that inherits the binder class and implements the methods in the Aidl interface, and we must inherit the stub class and implement its methods.
- Exposing the interface to the client
Implements the service class, overrides the onBind()
method, and returns the implementation of the stub.
Note: Changes to the Aidl interface after our first release are guaranteed to be compatible with the original version, to prevent other applications from accessing our service (which other clients may copy or the original interface version).
These steps are described in more detail below:
1. Create
.aidl
File
Aidl needs to satisfy some simple syntax: It enables us to declare an interface that can contain one or more methods and can have parameters and return values. The parameters and return values can be any type or even other aidl generated interfaces.
Each .aidl
file must define an interface, and only interface declarations and method declarations are required.
By default, AIDL supports the following data types:
- Eight basic data types in Java
- String
- Charsequence
- List
Of course, the types in the list also need to be aidl supported types. A variable is typically declared with a list, and the specific type (for example, ArrayList) is determined at the time of definition.
- Map
The same as list usage.
If you use a type other than the above (for example, a custom class), you must import the relevant declaration, even if it is defined in the same package.
When defining the Aidl interface, the following points need to be noted:
- The method can have 0 or more parameters, and you can choose to have no return value.
- All non-basic data types need to specify a direction to mark the flow of data (in, out, in and out of the same time). The base data type is entered by default and cannot be changed. It is necessary to limit the direction of the data (the direction that is really needed) because the cost of the marshalling parameter is very expensive.
- All code comments in the file are included in the generated IBinder interface, unless they are commented before the import and package.
- Only methods are supported and static member variables are not supported. And the method cannot have modifiers.
- Need to enter the package name manually (Android studio does not need to be manually)
Here's an example:
PackageCom.sywyg.servicetest;ImportCom.sywyg.servicetest.Man;//Declare any non-default types here with import statements//need to import the location of the custom typeInterface iremoteservice{/** Request The process ID of this service, to do evil things with it. * / intGetpid ();/** demonstrates some basic types that's can use as parameters * and return values in Aidl. */ voidBasictypes (intAnint,LongAlong,BooleanAboolean,floatAfloat,DoubleAdouble, String astring);//Man Getman ();}
The system will then automatically generate a Iremoteservice.java (corresponding iremoteservice.aidl) file.
Some compilers are generated immediately, while others are generated when the application is compiled, which is noted.
2. Implementing the interface
The auto-generated file contains an internal abstract class stub that inherits the binder and is an abstract implementation of the parent class interface, implementing .aidl
all the methods in the file. The stub also defines some other useful methods, especially the asInterface()
method, which receives a IBinder object and returns the implementation of the stub interface. Stub English denotes the meaning of the stub, the class on the server side of the process, we must inherit the class and implement the methods in the Aidl interface.
The following is a simple interface instance implemented with an anonymous class:
/** * Define an anonymous inner class implementation Aidl interface, need to inherit iremoteservice.stub class * methods declared in the. aidl file need to be implemented here for specific functions */ Private FinalIremoteservice.stub Mbinder =NewIremoteservice.stub () { Public int Getpid() {LOG.D (TAG,"Getpid is executed ...");returnAndroid.os.Process.myPid (); } Public void Basictypes(intAnint,LongAlong,BooleanAboolean,floatAfloat,DoubleAdouble, String astring) {log.d (TAG,"Basictypes is executed ..."); } };
The stub implements the Binder class (which defines the remote procedure call protocol remote Procedure called Protocol RPC), so the mbinder can be transmitted to the client.
There are a few things to consider when implementing AIDL:
- Calls are not guaranteed to execute in the main thread, we should consider multithreading issues and ensure that the service is thread safe.
- By default, RPC calls are asynchronous. If the service requires a long operation to ensure that the call cannot occur in the main thread, this may occur because the application cannot respond to the problem application not responding ANR. So we should make sure that the call happens in another child thread.
- Does not throw an exception to the caller.
3. Exposing the interface to the client
To implement the Aidl interface for the service, we should expose the interface to the client so that they can bind it. The complete code is given below to illustrate how to implement:
/** * IPC * via Aidl * @author sywyg * @since 2015.7.16 * * Public class aidlservice extends Service { Private FinalString TAG ="Result"; Public Aidlservice() { }/** * Define an anonymous inner class implementation Aidl interface, need to inherit iremoteservice.stub class * methods declared in the. aidl file need to be implemented here for specific functions */ Private FinalIremoteservice.stub Mbinder =NewIremoteservice.stub () { Public int Getpid() {LOG.D (TAG,"Getpid is executed ...");returnAndroid.os.Process.myPid (); } Public void Basictypes(intAnint,LongAlong,BooleanAboolean,floatAfloat,DoubleAdouble, String astring) {log.d (TAG,"Basictypes is executed ..."); } };@Override PublicIBinderOnbind(Intent Intent) {returnMbinder; }}
Then, when the client invokes the bindService()
connection service, the client callback onServiceConnected()
method receives the Mbinder instance (returned by the service's onBinder()
method).
The client must also be able to obtain the interface class, so when the client and service are in different applications, the client application must replicate a .aidl
file in order to get the method in Aidl.
When a customer onServiceConnected()
receives a IBinder object in a method, it must be YourServiceInterface.Stub.asInterface(service)
converted to the Yourserviceinterface type by calling. As follows:
Iremoteservice Miremoteservice;PrivateServiceconnection mconnection =NewServiceconnection () {@Override Public void onserviceconnected(componentname name, IBinder service) {LOG.D (TAG,"Bind succeeded");//Following the example above for an Aidl interface, //This gets a instance of the Iremoteservice, which we can use the service //or follow the example above to get an example of iremoteservice in this way, //So that we can process it on the client. Miremoteservice = IRemoteService.Stub.asInterface (service); Mbound =true; }@Override Public void onservicedisconnected(componentname name) {Mbound =false; } };
Passing objects through the IPC
We can implement the transfer of objects from one process to another through the IPC. However, we have to make sure that the object is available in another process (that is, the code that needs the class), and that the class needs to support the Parcelable interface. Parcelable must be supported so that the system can decompose objects into basic data types (capable of marshalled across processes).
Note: parcelable is an interface where class instances that implement the interface can be saved and recovered from the parcel. The class must have a static member variable called Creator, which is an implementation instance of Parcelable.creator.
In order to create a class that supports the Parcelable protocol, you must complete the following points:
- The class must implement the Parcelable interface;
- Implement the
writeToParcel()和
method, record the state of the current object (member variables, etc.), and save it with parcel. Also to achieve describeContents()
, generally return 0;
- Add static member variable Crearor, which is an implementation instance of Parcelable.creator;
- Finally, create a
.aidl
file that declares the Parcelable class (for example, the following Rect.aidl file). If you are doing a custom build process, do not add the .aidl
file because it is similar to the C language header file and will not be compiled. Dazed
Aidl produces Marshall and Unmarshall objects through the above methods.
Here is a class that implements the Parcelable interface, rect, first with the Rect.aidl file:
package android.graphics;// Declare Rect so AIDL can find it and knows that it implements// the parcelable protocol.// 声明Rect,AIDL好找到并确认它实现了parcelable协议parcelable Rect;
The following is the Rect class:
ImportAndroid.os.Parcel;Importandroid.os.Parcelable; Public Final class Rect implements parcelable { Public intLeft Public intTop Public intRight Public intBottom Public Static FinalParcelable.creator<rect> Creator =NewParcelable.creator<rect> () { PublicRectCreatefromparcel(Parcel in) {return NewRect (in); } PublicRect[]NewArray(intSize) {return NewRect[size]; } }; Public Rect() { }Private Rect(Parcel in) {Readfromparcel (in); } Public void Writetoparcel(Parcel out) {Out.writeint (left); Out.writeint (top); Out.writeint (right); Out.writeint (bottom); } Public void Readfromparcel(Parcel in) {left = In.readint (); top = In.readint (); right = In.readint (); Bottom = In.readint (); }}
Parcel can also write other types of data.
Warning: Do not forget about security issues when fetching data from another process. In the above example, rect gets four numbers, but it depends on how much data you get (the read-write order is consistent).
Calling the IPC method
The client must complete the following steps to implement the call to the remote interface:
- Include files in your project
.aidl
.
- Declares an instance of an IBinder object (based on Aidl).
- Implement Serviceconnection.
- Call
Context.bindService()
, and pass the serviceconnection implementation.
- In the
onServiceConnected()
implementation, we can accept an instance of IBinder (called service). The call is asInterface()
converted into an interface instance.
- Invokes the method defined in the interface. You must catch the Deadobjectionexception exception (when the connection is broken), which is the only exception that calls the remote method.
- Call to
Context.unBindService()
disassociate.
Call IPC Service considerations:
- Objects are reference types across process counts, as in the previous chapter, which can cause memory leaks.
- Ability to send anonymous objects as method parameters.
Interpreting the Android Service (3) Aidl