3

I have an Android Service which exports an RPC interface via AIDL. The interface is connection-oriented, where a client will connect to it, transact with it, then disconnect on exit.

Unfortunately is the client exits abnormally, e.g. gets killed by the system, it never gets the chance to tell the RPC interface that the connection has closed. This is causing problems.

Is there any way for a Service to get automatically notified when a new client attaches and detaches itself from an interface? I've found onBind() and onUnbind(), but they're not the same thing; they tell me whether the interface is in use or not. onUnbind() only gets called when the last client detaches.

Any ideas? (And the design of the service is controlled by external requirements and can't be changed...)

Update: I totally forgot to mention that I've looked at linkToDeath(), which almost does exactly what I want, but it only seems to work the opposite way round --- it allows a client to get notified when the Service dies. When I tried it nothing seemed to happen. The documentation's a little patchy; anyone know for sure whether this works how I want? And if so, how to get it to tell me which client died?

Update update: I have solved this problem, but only by cheating. I redefined it. My app is actually mostly written in C using the NDK, hence the odd design of the service; so, I moved the problem into the C world and created a tiny helper process which talks directly to the native parts of my app using Unix domain sockets. It's fast, very small, and almost bulletproof --- but it's still cheating. So while my problem is now solved, I'd still like to know what the actual answer is.

Onik
  • 15,592
  • 10
  • 57
  • 79
David Given
  • 12,261
  • 6
  • 63
  • 114
  • When you say it can't be changed, is it permissible to ADD methods to the exported interface,as long as you don't change the existing methods? Or maybe have the service send broadcasts whose intents could be picked up externally via broadcastreceivers? – NickT Oct 27 '11 at 18:23
  • I can change the interface all I like, but the overall connection-oriented architecture has to remain. I could have the service continually send out broadcasts which the clients have to reply to, and it assumes that clients which don't reply have died, but... ew. Is that what you meant? (Hey, if it'll work I'll try it.) – David Given Oct 27 '11 at 20:56

2 Answers2

2

Use linkToDeath() (but do it the other way around) by initializing new Binder object on your client side and send it via the AIDL to the service.
Then you can register to your client's DeathRecipient inside your service and get notified by the framework when the client's process exits abnormally.

Code Example -

Inside your .AIDL file - Create a method to pass the Binder object from the client to the service

void registerProcessDeath(in IBinder clientDeathListener);

On the client side - Initialize a new object and pass it to your service via AIDL interface.

public void onServiceConnected(ComponentName className, IBinder service) {
    mIMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);
    //Call the registerProcessDeath method from the AIDL file and pass 
    //the new Binder object
    mIMyAidlInterface.registerProcessDeath(new Binder());
}

On the service side - Get the client's Binder and register to his linkToDeath().

private IBinder mBinder; //Instance variable

private final IMyAidlInterface.Stub mStub = new IMyAidlInterface.Stub() {

    @Override
    public void registerProcessDeath(IBinder clientDeathListener) {
        mBinder = clientDeathListener;
        //Create new anonymous class of IBinder.DeathRecipient()
        clientDeathListener.linkToDeath(new IBinder.DeathRecipient() {
               @Override
               public void binderDied() {
               //Do your stuff when process exits abnormally here.
               //Unregister from client death recipient
               mBinder.unlinkToDeath(this,0);
               }
        },0);
    }
};

Additional reading - This mechanisem is very common inside the framework in order to prevent memory leaks on processes deaths - Very good tutorial by Alex Lockwood on the subject here.

Nir Duan
  • 5,310
  • 4
  • 20
  • 38
2

Maybe linkToDeath() can help here.

Adeel Ahmad
  • 829
  • 1
  • 9
  • 18
JimmyB
  • 11,178
  • 1
  • 23
  • 42
  • I forgot to mention linkToDeath() --- see update. Thanks for the reminder. – David Given Oct 27 '11 at 20:52
  • Looking at this [RemoteCallbackList](http://www.devdaily.com/java/jwarehouse/android/core/java/android/os/RemoteCallbackList.java.shtml) I would say you're right: Death is announced if/when the *provider* of the IInterface dies. This may provide a solution -alas not a pretty one- if you require your clients to register some (dummy) callback with your service. Once a client dies, its (dummy) callback interface will die, too, notifying your service. – JimmyB Oct 28 '11 at 07:22
  • Ah. That sounds plausible; I'll check it out. (My alternative plan is to force each client into its own process, notify the Service of its pid, and then have the Service monitor /proc to see if the processes go away; so I have a pretty high bar to the amount of ugliness I can tolerate to avoid having to do that!) – David Given Oct 28 '11 at 09:33