Binder is the core of Android's interprocess communication, if you look at the Android source code, you will find that the source of Android's various core services are through the binder mechanism to communicate with each other. In the client part of binder, the server side is accessed through proxy mode. This is to introduce the Java Layer Binder in detail through proxy mode. In this paper, we will briefly introduce the proxy mode and introduce the binder mechanism in detail. (source code based on 6.0.1)
Proxy mode Intent
Provides a proxy for other objects to control access to this object.
UML diagram
code example
AbstractClass subject{ Public Abstract void operate(); } class realsubject{ Public void operate() {System.out.println ("Real Operate"); }} class proxy{PrivateSubject Realsubject; Proxy (Subject Subject) {realsubject = Subject; } Public void operate() {realsubject.operate (); } } Public Static void Main(string[] args) {Realsubject Real =NewRealsubject (); Proxy proxy =NewProxy (real); Proxy.operate ();//actually handed over to the Realsubject to operate. }
About proxy mode
The above code is just an example of a UML diagram and does not fully describe the proxy pattern. Agent mode is to emphasize a proxy, the above example is in fact directly with the realsubject can be, there is no need to use proxy. In addition the proxy and the Proxied object do not require a common parent class/interface. There are several common scenarios for proxy mode:
-Remote Proxy: If an object cannot be instantiated and is not in the same address space, it needs to be encoded for communication. For example, you need to access an object operation above the network server. For example, the binder we need to introduce next.
-Virtual agent (virtual proxy): When needed to create large objects, such as large images, we can use a virtual proxy proxy image, when it is really necessary to get the image fully loaded, before this only need to save the image in the agent size, so that it has a placeholder for the good.
-Protection agent (Protect proxy): Some operations of an object need to be hidden, so it can be hidden by using a proxy.
-Smart Reference: When you need to count references to objects, you can use the proxy mode of smart guidance.
Binder
Binder is an interface form of IPC. Here is an example of the interface generated by the. aidl file that we used in the application development process. The use of aidl needs to be explained in the official Android documentation above:
The necessary condition for using aidl is that your service wants to be called by other clients from different applications for IPC and wants to handle multithreading in your service. If you don't need to parallelize the IPC from different applications, then you just need to use the implementation binder, and if you don't have to deal with multithreaded parallelism, then you can use Messenger.
This is just to illustrate Binder, named Itestservice.aidl:
com.houzhi.testproject;interface ITestService{ String getContent();}
The Android IDE (eclipse/android Studio) automatically generates related classes, itestservice.stub, Itestservice.proxy, before the compilation runs, And we can get the agent of binder by calling Bindservice.
Intent service; //只是为了表明类型ServiceConnection connection = new ServiceConnection(){ public void onServiceConnected(ComponetName name, IBinder service){ ITestService testService = ITestService.stub.asInterface(service); //testService就是我们得到的代理 } public void onServiceDisConnected(ComponentName name){ }}context.bindService(service,connection);
The UML diagram for the entire auto-generated class and binder, IInterface, is as follows:
ITestService.stub.asInterface(service)
Inside is the creation of a proxy object whose implementation code is as follows:
public staticcom. Houzhi. TestProject. ImyaidlinterfaceAsinterface (Android. OS. IBinderobj) {if ((obj = = null)) {return null;} Android. OS. IInterfaceIin = obj. Querylocalinterface(descriptor);if ((iin! = null) && (iin instanceofcom. Houzhi. TestProject. Imyaidlinterface)) {return (com. Houzhi. TestProject. Imyaidlinterface) iin);} return newcom. Houzhi. TestProject. Imyaidlinterface. Stub. Proxy(obj);}
The above code should indicate that the querylocalinterface of obj will return null, because obj is actually a binderproxy type, and the Binderproxy class does not add a corresponding iinterface to descriptor. In the source code in the specific implementation of the native layer, native through the way of JNI mobject (equivalent to the corresponding object Id,binderproxy member variable) created a binderproxy. Return this binderproxy to the client.
From the UML diagram we have seen that binder is a very typical proxy mode, is a remote proxy, in fact proxy agent is another process stub object. Internal is to mark the interface function as the corresponding ID, and then according to this ID to identify which function is currently called. The different interface calls are separated by descriptor as tokens, and the function parameters and the accepted function return values are written by parcel (the stub side corresponds to the Accept parameter and the result of the write). Aidl acceptable types are also common types (int,double ...), and map,list,string,
Charsequence,parcel, and binder types. The corresponding processing is not the same, but after all, you can use the basic way to get it done.
Here is a stub and proxy specific code for the implementation of the interface function:
Public Static Abstract class Stub extends android. os. Binder Implements com. Houzhi. TestProject. Itestservice { Private Static FinalJava.lang.String descriptor ="Com.houzhi.testproject.ITestService";//omitted part of the code @Override Public Boolean ontransact(intCode, Android.os.Parcel data, android.os.Parcel reply,intFlagsthrowsandroid.os.RemoteException {Switch(code) { CaseInterface_transaction: {reply.writestring (descriptor);return true; } CaseTransaction_getcontent: {data.enforceinterface (descriptor); Java.lang.String _result = This. getcontent (); Reply.writenoexception (); Reply.writestring (_result);return true; } }return Super. Ontransact (Code, data, reply, flags); }Private Static class Proxy implements com. Houzhi. TestProject. Itestservice { PrivateAndroid.os.IBinder Mremote; Proxy (Android.os.IBinder remote) {mremote = remote; }//omitted part of the code @Override PublicJava.lang.Stringgetcontent()throwsandroid.os.RemoteException {Android.os.Parcel _data = Android.os.Parcel.obtain (); Android.os.Parcel _reply = Android.os.Parcel.obtain (); Java.lang.String _result;Try{_data.writeinterfacetoken (descriptor); Mremote.transact (Stub.transaction_getcontent, _data, _reply,0); _reply.readexception (); _result = _reply.readstring (); }finally{_reply.recycle (); _data.recycle (); }return_result; } }Static Final intTransaction_getcontent = (Android.os.IBinder.FIRST_CALL_TRANSACTION +0); }
A brief introduction to binder bottom implementation
After reading the previous section, you can actually think of how to implement binder, the interface call request into the form of data flow, the ID of the type int is the specific function, using token to partition each function call request, according to function parameter order and type one by one to write and read parameters. And at the bottom through a process of communication (Pipe, shared memory) to send these messages to the server/client, so it can be roughly implemented. In fact, the binder driver is used at the bottom, and the server opens a thread via Ipcthreadstate (Ipcthreadstate::self ()->startthreadpool ()). and puts the thread into line Cheng (Ipcthreadstate::self ()->jointhreadpool ()), waiting to receive a request from the client (Talkwithdriver ()). Instead, the client accesses the binder (Talkwithdriver ()) by Binderproxy (internally holding the local bpbinder pointer) of the Transact. Internal use of access-driven functions is both ioctl.
ServiceManager
The above describes the service side, the client and binder driver communication process. But have you ever wondered, how do I know which server I want to request when the client needs to request the server? ServiceManager. ServiceManager is the FD (driver file number) that saved all the service. The getService(String name)
corresponding service can be obtained by requesting servicemanager. And ServiceManager is also a service, its FD is 0, is the Service center manager. The client specifies name, requests ServiceManager through binder, and then gets the service binderproxy that the client wants, and can then request the server. Of course, when creating a service, you first need to add the service to ServiceManager through Servicemanager.addservice.
Several large modules of binder connections
Some of the most important modules used in the Android application layer are made up of binders, Activitymanagerservice,windowmanagerservice,inputmanagerservice. Here is a diagram of their relationship:
There are many other services, such as Wifi,networkpolicy,power and so on. They are all registered in the Systemserviceregistry, this registration was originally in the Contextimpl, now moved to a separate class systemserviceregistry.
Application analysis of Agent mode in binder
The proxy mode used here is basically seamless, and I think this is the classic use of proxy mode. We do not have direct access to the server on the client side (because the cross-process, the address space is inconsistent), through the proxy mode, allows us to feel as if the client directly access the server side.
If you shed tears when you miss the Sun, you also miss the stars.
Android Source Agent Mode---Binder