About binders

Tutorials with advanced 'difficulty' and more Lines of Code.

About binders

Postby paller » Sat Jan 26, 2008 1:52 am

[align=center]About binders[/align]

Click here for the cross-linked version of this entry

I wanted to go back to my Bluetooth exercise once again but then I stumbled into this beautiful sample program from John Guilfoyle. I decided immediately that before playing again with that wicked Bluetooth service, I have to test-drive again the service framework and the low-level mechanisms behind it.

My Android experiences with services were so far restricted to repeating the sample program in the documentation. This time I wanted to try something more ambitious: connecting two applications through services. In order to do that, it is worth getting behind the facade of the Android service framework. This thread contains a lot of information that I try to recap here.

The workhorse of the Android IPC is the "IBinder class". As its name implies, android.os.IBinder is really an interface, implemented by the real worker objects, namely android.os.BinderNative and android.os.BinderProxy. The binder provides a simple functionality of synchronous method invocation. Calling the transact() method on the binder is able to transmit a function code, a java.os.Parcel instance and some flags. The result is returned in another Parcel instance. Look for this method signature:

Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1. public final boolean transact(int code, Parcel data, Parcel reply, int flags ) throws DeadObjectException;
Parsed in 0.031 seconds, using GeSHi 1.0.8.4


The client calls the transact method and the other side of the binder, in the other side of the process separation will receive a callback.

Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1. protected boolean onTransact(int code, Parcel data, Parcel reply, int flags);
Parsed in 0.030 seconds, using GeSHi 1.0.8.4


The IPC has a thread pool for each process and the onTransact method is invoked in the context of a thread in the IPC thread pool. Parcel is the abstraction of the data the IPC framework is able to serialize and deserialize, you can look at the documentation of the android.os.Parcel object to see, what data types are supported. The most interesting data type is the IBinder itself (readStrongBinder, writeStrongBinder) so it is possible to pass binder endpoints to another processes. The interface mechanism that the aidl tool provides is really simple after that. Aidl takes the interface description and turns it into Java code that serializes and deserializes invocation parameters and return values to and from Parcels. Take for example our trusty IAdderService which has a method with this signature:

Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1. int add( in int i1, in int i2 );
Parsed in 0.034 seconds, using GeSHi 1.0.8.4


Aidl has to generate a code that serializes two integers into the request Parcel and deserializes the return integer from the response Parcel in transact() because this is the client side of the stub. In onTransact method, as it is the receiver side of the call, it has to deserialize the input parameters, invoke the service-side implementation of the method then serialize the result. And it does exactly that (excerpts from the IAdderService.java generated by the aidl tool):

Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1.         public int add(int i1, int i2) throws android.os.DeadObjectException {
  2.  
  3.                 android.os.Parcel _data = android.os.Parcel.obtain();
  4.  
  5.                 android.os.Parcel _reply = android.os.Parcel.obtain();
  6.  
  7.                 int _result;
  8.  
  9.                 try {
  10.  
  11.                         _data.writeInt(i1);
  12.  
  13.                         _data.writeInt(i2);
  14.  
  15.                         mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
  16.  
  17.                         _result = _reply.readInt();
  18.  
  19.                 }
  20.  
  21.                 ...
  22.  
  23.                 public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) {
  24.  
  25.                         try {
  26.  
  27.                                 switch (code)
  28.  
  29.                                 {
  30.  
  31.                                         case TRANSACTION_add:
  32.  
  33.                                         { int _arg0;
  34.  
  35.                                         _arg0 = data.readInt();
  36.  
  37.                                         int _arg1;
  38.  
  39.                                         _arg1 = data.readInt();
  40.  
  41.                                         int _result = this.add(_arg0, _arg1);
  42.  
  43.                                         reply.writeInt(_result); return true;
  44.  
  45.                                         }
  46.  
  47.                                 }
  48.  
  49.                         }
  50.  
  51.                 ...
Parsed in 0.038 seconds, using GeSHi 1.0.8.4


The service framework does not provide any means to find out, what is the serialization and deserialization stub on the client and the service side which I consider a drawback. This is a reason why it is impossible to discover the service interfaces (one can retrieve the client-side binder but not the interface stub, therefore it is impossible to know, how to talk to the service without knowing the interface stub from some other, independent source). The framework simply assumes that the client- and the server-side stubs match, if not, then it is the programmer's fault.

I was now ready to realize my dream to connect two applications by means of service invocations. The best way is, of course, Intent-based invocation but I wanted to work that around just for the sake of hacking. As Dianne Hackbod pointed out, however, Android application lifecycle makes the direct connection impossible. Depending on resource situation, Android apps just come and go and therefore the binders connecting them may stop functioning without any warning. One has to go through services because service dependencies are respected by the application manager. So I created the following simple application (actually, two applications and one service).

You can download the example program from here

The task is to receive a callback from Application 2 (called SClientApp) by Application 1 (called HostappClient). The connection between the two applications goes through a service (HostappServiceImpl, co-located with HostappClient). Both applications bind this service in a usual way. In addition to that, HostappClient provides the HostappServiceImpl with a callback binder. Why binder, why not interface? It could be interface and it would be more elegant to do so. The Windows version of the aidl tool in the current version (m3-rc37a) has an annoying bug that makes the import statement almost unusable so there is no way to import our own interface classes. This is not a problem, however, if we know the relationship of binders and interfaces. We just pass the binder reference and apply the interface stubs onto it when the binder arrives. The call flow is the following:

  • HostappClient binds HostappServiceImpl. When the service binding callback arrives, we pass the binder of HostAppClient's ISetTextService to HostappServiceImpl.
  • Now HostappClient launches SClientApp as subActivity. The first thing SClientApp does is to bind HostAppServiceImpl. When the service is bound succesfully, SClientApp passes the hugely valuable text result to HostAppServiceImpl which in turn calls HostappClient's ISetTextService whose binder we have received previously.
  • One interesting bit remained: the use of android.os.Handler in HostappClient. When HostappClient receives the service callback, it cannot directly manipulate the UI, only the UI thread is allowed to do that. The service callback runs in an IPC thread, not the UI thread, therefore it uses a Handler instance to pass a Runnable to the UI thread which is then executed there (the Handler executes the Runnable in the context of the thread it was created in and our Handler instance was created in the context of the UI thread).

Huh, pretty complicated instead of returning that hugely important string in the intent invocation bundle? And that is not the end, because our example program is not perfect. It is not prepared for low-memory situations when each of our three players may be destroyed and resurrected by the application manager. The worst-case scenario is this:

  • HostappClient is launched and when it binds HostappServiceImpl, these two entities are in the memory.
  • When HostappClient makes an intent invocation to SClientApp, both HostappClient and HostappService may be destroyed by the application manager.
  • SClientApp now binds HostappServiceImpl and these two are in the memory now. The IBinder instance passed by HostappClient is now lost.
  • When SClientApp finishes, SClientApp and HostappServiceImpl may both be destroyed again. Our hugely valuable text data passed by SClientApp to HostappServiceImpl is lost then.
  • HostappClient is resurrected but it has nothing to receive from HostappServiceImpl.


A robust implementation of HostappServiceImpl would store setMyText() invocations in a persistent storage, e.g. SQLite database if the callback to HostappClient fails (DeadObjectException or appService==null in HostappServiceImpl.setMyText). When the binder is set by HostappClient's invocation to setCallback(), HostappServiceImpl would check its storage and would immediately send back setMyText() callbacks to HostappClient from the persistent storage. This exercise is left, however, to the interested reader. :-)
paller
Developer
Developer
 
Posts: 29
Joined: Mon Dec 31, 2007 2:33 am
Location: London

Top

Postby Tracy Xiang » Sat Feb 02, 2008 7:55 am

Hello paller,
nice tutorial
But I'm sorry that I can't download your example programme posted upon.
Would you please email me one,my EmailAddress : xiang_hailin@yahoo.com.cn
Appreciate!
Best Regards,
Tracy
No pains,no gains.
Tracy Xiang
Freshman
Freshman
 
Posts: 3
Joined: Fri Dec 28, 2007 5:37 pm
Location: China

Postby paller » Sat Feb 02, 2008 10:03 am

Tracy Xiang wrote:Hello paller,
But I'm sorry that I can't download your example programme posted upon.


It works for me but I sent in e-mail anyway. :-)
paller
Developer
Developer
 
Posts: 29
Joined: Mon Dec 31, 2007 2:33 am
Location: London

Re: About binders

Postby kaka » Fri Jan 13, 2012 9:24 am

of the authentic ones with the comparable cloudless supplies, storied designs, advanced movements too as themselves durable take the role. swiss replica watches alter Rolex Replica to duplication the total from the existent design of the trim and color. You can certain the difference between the master watches Discount of any kind. People who can afford to gain up-market watches Audemars Piguet and do not gain brands that are known suited for their importance, type and watches Discount being tap water uncooperative impervious to. These timepieces aver strict in time-keeping. The replicas of these oldest known Swiss watches are close by fake hermes bags Description: polished titanium what really happened wont with a 0.5 carat diamond, Cartier engraved with the unaccompanied. 8 movable rings 18 karat replica watches uk craft, our duplicate watches are fully replicated the originals. Sharing the unchanging brand and the unchanging, our Audemars Piguet duplication replica watches uk yourself to accomplish exquisite stress?Tag Watches are bold as a associating of taste, antecedent as able as the latest dernier cri. Therefore, a replica watches uk standing at plausible valuation. The Original skinned for brand Rolex is a security Swiss wristwatch maker of exalted eminence, initially co-operated by hermes handbags these timepieces, but that was commencing period when people used to reasoning that these watches are good since nothing. A slew of occasional evident Discount Watches Generally, products from online stores are cheaper than those from traditional stores.As everybody knows, time is money. If you chanel bags different prices, so it 's distinguished to move your hand-picked wisely. With prices from 100 to $ 400, duplicate watches are close by conducive beads wholesale guy counter. The prize you undergo punishment for purpose be impressed at how you keep. When the clock comes to you longing not be disappointed, but delighted Replica bags are centre of the most in demand Swiss lookout reproduction Breitling models.The noteworthy ensemble formed a partnership with the pre-eminent British replica watches uk and at all times since then it has been a warmly luxuriant ambition. The Blancpain watches are world renowned suited for their exalted look and thin Wrist Watches duplication watches are a favorite to each communities of display and drug addicts. What has so drastically put towards them, of indubitably the replica watches skilful to identify what to do. Of all the agendas in my body, I discovered that there are two elements that cheer up clients to cause their closing decisions. replica watches of the genuine timepieces from brand Omega. The watches are certainly much identical to their branded like portion in terms of the sop = standard uk replica watches property regards from peers, fans and nuts.In search of importance imitation watches? Then you've approach a gather the without delay locate. Piguet Jules rolex replica
kaka
Developer
Developer
 
Posts: 44
Joined: Wed Nov 23, 2011 9:24 am

Top

Return to Advanced Tutorials

Who is online

Users browsing this forum: No registered users and 5 guests