3

我有一个 VpnService 的自定义实现,它需要在断开连接时执行一些额外的清理。当我使用服务绑定从我的应用程序中停止 VpnService 时,一切正常,但是当客户端使用系统对话框从 Vpn 断开连接时,我需要执行该清理。

那么,我怎样才能捕捉到断开连接并添加一些处理呢?

在 Android 上获取 VPN 连接状态- 这可能是解决方案,但它不适用于 android 4+。

从日志的角度来看,只有两个条目:

03-20 03:27:09.478: INFO/Vpn(504): Switched from org.my.package to [Legacy VPN] 03-20 03:27:09.478: DEBUG/Vpn(504): setting state=IDLE, reason=prepare

4

2 回答 2

14

我刚刚遇到了同样的问题。不调用 VpnService.onRevoke()。

事实证明,这是因为我使用了一个通过 AIDL 定义的自定义 IBinder,我从 onBind() 返回。VpnService 也实现了 onBind() 并返回 VpnService.Callback 的实例。以这种方式实现:

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 不使用 AIDL,只检查函数代码 IBinder.LAST_CALL_TRANSACTION 是否已发送。如果是,则执行 onRevoke()。

我将此代码片段集成到我的自定义 IBinder 实现中,现在我收到 onRevoke() 消息。请参见以下示例:

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()
    }
}

我是怎么想出来的?我在 android 源代码中搜索了实际调用 onRevoke() 的位置。为此,我发现grepcode (android)非常有用。我经常阅读 android 源代码以了解事情是如何工作的。

于 2013-03-31T16:07:41.790 回答
3

事实证明,这是因为我使用了一个通过 AIDL 定义的自定义 IBinder,我从 onBind() 返回。VpnService 也实现了 onBind() 并返回 VpnService.Callback 的实例。

是的,它是正确的。所以,我认为这是另一种解决方法:

@Override
public IBinder onBind(Intent intent) {
    String action = null;
    if (intent != null) {
        action = intent.getAction();
    }

    if (VpnService.SERVICE_INTERFACE == action) {
        return super.onBind(intent);
    }

    return yourBinder;
}
于 2016-09-20T10:36:10.537 回答