Getting notified when clients attach and detach to an Android Service

7.3k Views Asked by At

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.

2

There are 2 best solutions below

3
On

Maybe linkToDeath() can help here.

0
On

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.