This can be done by the Binder.linkToDeath()
mechanism - You'll have to ask each client to send new Binder()
object that they initiated and then link to their (your clients') death.
I'll explain how to preform this using AIDL files.
(You can choose any android IPC mechanism as long as you can pass Binder objects from your client's to your service)
Code Example -
Inside your .AIDL
file - Create a method to pass the IBinder
object from the client to the service
void registerProcessDeath(in IBinder clientDeathListener, String packageName);
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 and the client's package name
mIMyAidlInterface.registerProcessDeath(new Binder(),getPackageName());
}
On the service side -
1. Get the client's Binder
and register to his linkToDeath()
.
2. Use helper class to handle all clients via android's IBinder.DeathRecipient class
public class MyService extends Service {
//Helper class to handle all client's deaths.
private volatile ClientsDeathWatcher mClientsList;
@Override
public IBinder onBind(Intent intent) {
mClientsList = new ClientsDeathWatcher();
return mStub;
}
private final IMyAidlInterface.Stub mStub = new IMyAidlInterface.Stub() {
@Override
public void registerProcessDeath(IBinder cb, String packageName){
boolean isRegistered = mClientsList.register(cb , packageName);
}
};
}
//This is thread-safe helper class to handle all
//the client death related tasks.
//All you care abut is the clientDeath() method.
public class ClientsDeathWatcher {
private ArrayMap<String, DeathCallBack> mCallbacks = new ArrayMap<>();
private final class DeathCallBack implements IBinder.DeathRecipient {
private String pn;
private IBinder mBinder;
DeathCallBack(String packageName,IBinder binder) {
pn = packageName;
mBinder = binder;
}
public void binderDied() {
synchronized (mCallbacks) {
mBinder.unlinkToDeath(this,0);
clientDeath(pn);
}
}
}
//To be called only from thread-safe functions
private void clientDeath(String packageName) {
mCallbacks.remove(packageName);
//Do your stuff here.
//$$$$$$$$$
}
public boolean register(IBinder token, String packageName) {
synchronized (mCallbacks) {
try {
if (!mCallbacks.containsKey(packageName)) {
DeathCallBack mDeathCallBack = new DeathCallBack(packageName,token);
mCallbacks.put(packageName, mDeathCallBack);
//This is where the magic happens
token.linkToDeath(mDeathCallBack, 0);
}
return true;
} catch (RemoteException e) {
e.printStackTrace();
return false;
}
}
}
}
onUnbind
is handled deep within Android's framework and I'm not sure if that's even guaranteed to be called in your remote process case. – Nipha