I just ran into the same issue. VpnService.onRevoke() is not called.
It turns out this happens because I use a custom IBinder defined via AIDL wich I return from onBind(). VpnService implements onBind() too and returns an instance of VpnService.Callback.
Which is implemented this way:
private class Callback extends Binder {
@Override
protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) {
if (code == IBinder.LAST_CALL_TRANSACTION) {
onRevoke();
return true;
}
return false;
}
}
VpnService.Callback does not use AIDL and just checks if the function code IBinder.LAST_CALL_TRANSACTION was sent. If so it executes onRevoke().
I integrated this code fragment in my custom IBinder implementation and now I receive the onRevoke() message. See the following example:
private final IBinder mBinder = new ServiceBinder();
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
public final class ServiceBinder extends ICustomVpnService.Stub
{
... implement methods defined in ICustomVpnService.Stub ....
/**
* Intercept remote method calls and check for "onRevoke" code which
* is represented by IBinder.LAST_CALL_TRANSACTION. If onRevoke message
* was received, call onRevoke() otherwise delegate to super implementation.
*/
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException
{
// see Implementation of android.net.VpnService.Callback.onTransact()
if ( code == IBinder.LAST_CALL_TRANSACTION )
{
onRevoke();
return true;
}
return super.onTransact( code, data, reply, flags );
}
private void onRevoke()
{
// shutdown VpnService, e.g. call VpnService.stopSelf()
}
}
How did I figure it out? I searched the android source code for where onRevoke() is actually invoked. For that I find grepcode (android) pretty helpful. I often read the android source to understand how things work.