diff options
3 files changed, 81 insertions, 64 deletions
diff --git a/core/java/android/net/VpnProfileState.java b/core/java/android/net/VpnProfileState.java index 0f21a9d7f471..552a2c171f21 100644 --- a/core/java/android/net/VpnProfileState.java +++ b/core/java/android/net/VpnProfileState.java @@ -24,6 +24,7 @@ import android.os.Parcelable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.Objects; import java.util.StringJoiner; /** @@ -176,4 +177,19 @@ public final class VpnProfileState implements Parcelable { resultJoiner.add("Lockdown: " + isLockdownEnabled()); return resultJoiner.toString(); } + + @Override + public boolean equals(@Nullable Object obj) { + if (!(obj instanceof VpnProfileState)) return false; + final VpnProfileState that = (VpnProfileState) obj; + return (getState() == that.getState() + && Objects.equals(getSessionId(), that.getSessionId()) + && isAlwaysOn() == that.isAlwaysOn() + && isLockdownEnabled() == that.isLockdownEnabled()); + } + + @Override + public int hashCode() { + return Objects.hash(getState(), getSessionId(), isAlwaysOn(), isLockdownEnabled()); + } } diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index d9db28a9aa78..b49654e0f79b 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -2527,7 +2527,9 @@ public class Vpn { super(TAG); mProfile = profile; mIpSecManager = (IpSecManager) mContext.getSystemService(Context.IPSEC_SERVICE); - mNetworkCallback = new VpnIkev2Utils.Ikev2VpnNetworkCallback(TAG, this); + // Pass mExecutor into Ikev2VpnNetworkCallback and make sure that IkeV2VpnRunnerCallback + // will be called by the mExecutor thread. + mNetworkCallback = new VpnIkev2Utils.Ikev2VpnNetworkCallback(TAG, this, mExecutor); mSessionKey = UUID.randomUUID().toString(); } @@ -2682,73 +2684,68 @@ public class Vpn { * <p>The Ikev2VpnRunner will unconditionally switch to the new network, killing the old IKE * state in the process, and starting a new IkeSession instance. * - * <p>This method is called multiple times over the lifetime of the Ikev2VpnRunner, and is - * called on the ConnectivityService thread. Thus, the actual work MUST be proxied to the - * mExecutor thread in order to ensure consistency of the Ikev2VpnRunner fields. + * <p>This method MUST always be called on the mExecutor thread in order to ensure + * consistency of the Ikev2VpnRunner fields. */ public void onDefaultNetworkChanged(@NonNull Network network) { Log.d(TAG, "Starting IKEv2/IPsec session on new network: " + network); - // Proxy to the Ikev2VpnRunner (single-thread) executor to ensure consistency in lieu - // of locking. - mExecutor.execute(() -> { - try { - if (!mIsRunning) { - Log.d(TAG, "onDefaultNetworkChanged after exit"); - return; // VPN has been shut down. - } + try { + if (!mIsRunning) { + Log.d(TAG, "onDefaultNetworkChanged after exit"); + return; // VPN has been shut down. + } - // Clear mInterface to prevent Ikev2VpnRunner being cleared when - // interfaceRemoved() is called. - mInterface = null; - // Without MOBIKE, we have no way to seamlessly migrate. Close on old - // (non-default) network, and start the new one. - resetIkeState(); - mActiveNetwork = network; - - // Get Ike options from IkeTunnelConnectionParams if it's available in the - // profile. - final IkeTunnelConnectionParams ikeTunConnParams = - mProfile.getIkeTunnelConnectionParams(); - final IkeSessionParams ikeSessionParams; - final ChildSessionParams childSessionParams; - if (ikeTunConnParams != null) { - final IkeSessionParams.Builder builder = new IkeSessionParams.Builder( - ikeTunConnParams.getIkeSessionParams()).setNetwork(network); - ikeSessionParams = builder.build(); - childSessionParams = ikeTunConnParams.getTunnelModeChildSessionParams(); - } else { - ikeSessionParams = VpnIkev2Utils.buildIkeSessionParams( - mContext, mProfile, network); - childSessionParams = VpnIkev2Utils.buildChildSessionParams( - mProfile.getAllowedAlgorithms()); - } + // Clear mInterface to prevent Ikev2VpnRunner being cleared when + // interfaceRemoved() is called. + mInterface = null; + // Without MOBIKE, we have no way to seamlessly migrate. Close on old + // (non-default) network, and start the new one. + resetIkeState(); + mActiveNetwork = network; - // TODO: Remove the need for adding two unused addresses with - // IPsec tunnels. - final InetAddress address = InetAddress.getLocalHost(); - mTunnelIface = - mIpSecManager.createIpSecTunnelInterface( - address /* unused */, - address /* unused */, - network); - NetdUtils.setInterfaceUp(mNetd, mTunnelIface.getInterfaceName()); - - mSession = mIkev2SessionCreator.createIkeSession( - mContext, - ikeSessionParams, - childSessionParams, - mExecutor, - new VpnIkev2Utils.IkeSessionCallbackImpl( - TAG, IkeV2VpnRunner.this, network), - new VpnIkev2Utils.ChildSessionCallbackImpl( - TAG, IkeV2VpnRunner.this, network)); - Log.d(TAG, "Ike Session started for network " + network); - } catch (Exception e) { - Log.i(TAG, "Setup failed for network " + network + ". Aborting", e); - onSessionLost(network, e); + // Get Ike options from IkeTunnelConnectionParams if it's available in the + // profile. + final IkeTunnelConnectionParams ikeTunConnParams = + mProfile.getIkeTunnelConnectionParams(); + final IkeSessionParams ikeSessionParams; + final ChildSessionParams childSessionParams; + if (ikeTunConnParams != null) { + final IkeSessionParams.Builder builder = new IkeSessionParams.Builder( + ikeTunConnParams.getIkeSessionParams()).setNetwork(network); + ikeSessionParams = builder.build(); + childSessionParams = ikeTunConnParams.getTunnelModeChildSessionParams(); + } else { + ikeSessionParams = VpnIkev2Utils.buildIkeSessionParams( + mContext, mProfile, network); + childSessionParams = VpnIkev2Utils.buildChildSessionParams( + mProfile.getAllowedAlgorithms()); } - }); + + // TODO: Remove the need for adding two unused addresses with + // IPsec tunnels. + final InetAddress address = InetAddress.getLocalHost(); + mTunnelIface = + mIpSecManager.createIpSecTunnelInterface( + address /* unused */, + address /* unused */, + network); + NetdUtils.setInterfaceUp(mNetd, mTunnelIface.getInterfaceName()); + + mSession = mIkev2SessionCreator.createIkeSession( + mContext, + ikeSessionParams, + childSessionParams, + mExecutor, + new VpnIkev2Utils.IkeSessionCallbackImpl( + TAG, IkeV2VpnRunner.this, network), + new VpnIkev2Utils.ChildSessionCallbackImpl( + TAG, IkeV2VpnRunner.this, network)); + Log.d(TAG, "Ike Session started for network " + network); + } catch (Exception e) { + Log.i(TAG, "Setup failed for network " + network + ". Aborting", e); + onSessionLost(network, e); + } } /** Marks the state as FAILED, and disconnects. */ diff --git a/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java b/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java index a0a596d998bf..6982d6095689 100644 --- a/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java +++ b/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java @@ -86,6 +86,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.List; +import java.util.concurrent.ExecutorService; /** * Utility class to build and convert IKEv2/IPsec parameters. @@ -376,22 +377,25 @@ public class VpnIkev2Utils { static class Ikev2VpnNetworkCallback extends NetworkCallback { private final String mTag; private final Vpn.IkeV2VpnRunnerCallback mCallback; + private final ExecutorService mExecutor; - Ikev2VpnNetworkCallback(String tag, Vpn.IkeV2VpnRunnerCallback callback) { + Ikev2VpnNetworkCallback(String tag, Vpn.IkeV2VpnRunnerCallback callback, + ExecutorService executor) { mTag = tag; mCallback = callback; + mExecutor = executor; } @Override public void onAvailable(@NonNull Network network) { Log.d(mTag, "Starting IKEv2/IPsec session on new network: " + network); - mCallback.onDefaultNetworkChanged(network); + mExecutor.execute(() -> mCallback.onDefaultNetworkChanged(network)); } @Override public void onLost(@NonNull Network network) { Log.d(mTag, "Tearing down; lost network: " + network); - mCallback.onSessionLost(network, null); + mExecutor.execute(() -> mCallback.onSessionLost(network, null)); } } |