Merge "Make VPN more testable and update NC during network change" am: 9ff5caa8e5 am: 4cdb702532

Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/2115938

Change-Id: Ia2f66f8a7067eff751e51452a4adf17dc4f9d12b
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Yan Yan
2022-06-13 18:20:51 +00:00
committed by Automerger Merge Worker

View File

@@ -252,8 +252,7 @@ public class Vpn {
@VisibleForTesting @VisibleForTesting
protected VpnConfig mConfig; protected VpnConfig mConfig;
private final NetworkProvider mNetworkProvider; private final NetworkProvider mNetworkProvider;
@VisibleForTesting @VisibleForTesting protected VpnNetworkAgentWrapper mNetworkAgent;
protected NetworkAgent mNetworkAgent;
private final Looper mLooper; private final Looper mLooper;
@VisibleForTesting @VisibleForTesting
protected NetworkCapabilities mNetworkCapabilities; protected NetworkCapabilities mNetworkCapabilities;
@@ -498,6 +497,30 @@ public class Vpn {
return IKEV2_VPN_RETRY_DELAYS_SEC[retryCount]; return IKEV2_VPN_RETRY_DELAYS_SEC[retryCount];
} }
} }
/** Get single threaded executor for IKEv2 VPN */
public ScheduledThreadPoolExecutor getScheduledThreadPoolExecutor() {
return new ScheduledThreadPoolExecutor(1);
}
/** Get a VpnNetworkAgentWrapper instance */
public VpnNetworkAgentWrapper getVpnNetworkAgentWrapper(
@NonNull Context context,
@NonNull Looper looper,
@NonNull String logTag,
@NonNull NetworkCapabilities nc,
@NonNull LinkProperties lp,
@NonNull NetworkScore score,
@NonNull NetworkAgentConfig config,
@Nullable NetworkProvider provider) {
return new VpnNetworkAgentWrapper(
new NetworkAgent(context, looper, logTag, nc, lp, score, config, provider) {
@Override
public void onNetworkUnwanted() {
// We are user controlled, not driven by NetworkRequest.
}
});
}
} }
public Vpn(Looper looper, Context context, INetworkManagementService netService, INetd netd, public Vpn(Looper looper, Context context, INetworkManagementService netService, INetd netd,
@@ -1329,7 +1352,7 @@ public class Vpn {
@VisibleForTesting @VisibleForTesting
@Nullable @Nullable
public synchronized Network getNetwork() { public synchronized Network getNetwork() {
final NetworkAgent agent = mNetworkAgent; final VpnNetworkAgentWrapper agent = mNetworkAgent;
if (null == agent) return null; if (null == agent) return null;
final Network network = agent.getNetwork(); final Network network = agent.getNetwork();
if (null == network) return null; if (null == network) return null;
@@ -1409,7 +1432,8 @@ public class Vpn {
* registering a new NetworkAgent. This is not always possible if the new VPN configuration * registering a new NetworkAgent. This is not always possible if the new VPN configuration
* has certain changes, in which case this method would just return {@code false}. * has certain changes, in which case this method would just return {@code false}.
*/ */
private boolean updateLinkPropertiesInPlaceIfPossible(NetworkAgent agent, VpnConfig oldConfig) { private boolean updateLinkPropertiesInPlaceIfPossible(
VpnNetworkAgentWrapper agent, VpnConfig oldConfig) {
// NetworkAgentConfig cannot be updated without registering a new NetworkAgent. // NetworkAgentConfig cannot be updated without registering a new NetworkAgent.
if (oldConfig.allowBypass != mConfig.allowBypass) { if (oldConfig.allowBypass != mConfig.allowBypass) {
Log.i(TAG, "Handover not possible due to changes to allowBypass"); Log.i(TAG, "Handover not possible due to changes to allowBypass");
@@ -1474,15 +1498,11 @@ public class Vpn {
? Arrays.asList(mConfig.underlyingNetworks) : null); ? Arrays.asList(mConfig.underlyingNetworks) : null);
mNetworkCapabilities = capsBuilder.build(); mNetworkCapabilities = capsBuilder.build();
mNetworkAgent = new NetworkAgent(mContext, mLooper, NETWORKTYPE /* logtag */, mNetworkAgent = mDeps.getVpnNetworkAgentWrapper(
mContext, mLooper, NETWORKTYPE /* logtag */,
mNetworkCapabilities, lp, mNetworkCapabilities, lp,
new NetworkScore.Builder().setLegacyInt(VPN_DEFAULT_SCORE).build(), new NetworkScore.Builder().setLegacyInt(VPN_DEFAULT_SCORE).build(),
networkAgentConfig, mNetworkProvider) { networkAgentConfig, mNetworkProvider);
@Override
public void onNetworkUnwanted() {
// We are user controlled, not driven by NetworkRequest.
}
};
final long token = Binder.clearCallingIdentity(); final long token = Binder.clearCallingIdentity();
try { try {
mNetworkAgent.register(); mNetworkAgent.register();
@@ -1506,7 +1526,7 @@ public class Vpn {
} }
} }
private void agentDisconnect(NetworkAgent networkAgent) { private void agentDisconnect(VpnNetworkAgentWrapper networkAgent) {
if (networkAgent != null) { if (networkAgent != null) {
networkAgent.unregister(); networkAgent.unregister();
} }
@@ -1562,7 +1582,7 @@ public class Vpn {
VpnConfig oldConfig = mConfig; VpnConfig oldConfig = mConfig;
String oldInterface = mInterface; String oldInterface = mInterface;
Connection oldConnection = mConnection; Connection oldConnection = mConnection;
NetworkAgent oldNetworkAgent = mNetworkAgent; VpnNetworkAgentWrapper oldNetworkAgent = mNetworkAgent;
Set<Range<Integer>> oldUsers = mNetworkCapabilities.getUids(); Set<Range<Integer>> oldUsers = mNetworkCapabilities.getUids();
// Configure the interface. Abort if any of these steps fails. // Configure the interface. Abort if any of these steps fails.
@@ -2692,8 +2712,7 @@ public class Vpn {
* of the mutable Ikev2VpnRunner fields. The Ikev2VpnRunner is built mostly lock-free by * of the mutable Ikev2VpnRunner fields. The Ikev2VpnRunner is built mostly lock-free by
* virtue of everything being serialized on this executor. * virtue of everything being serialized on this executor.
*/ */
@NonNull @NonNull private final ScheduledThreadPoolExecutor mExecutor;
private final ScheduledThreadPoolExecutor mExecutor = new ScheduledThreadPoolExecutor(1);
@Nullable private ScheduledFuture<?> mScheduledHandleNetworkLostTimeout; @Nullable private ScheduledFuture<?> mScheduledHandleNetworkLostTimeout;
@Nullable private ScheduledFuture<?> mScheduledHandleRetryIkeSessionTimeout; @Nullable private ScheduledFuture<?> mScheduledHandleRetryIkeSessionTimeout;
@@ -2714,7 +2733,7 @@ public class Vpn {
@Nullable private LinkProperties mUnderlyingLinkProperties; @Nullable private LinkProperties mUnderlyingLinkProperties;
private final String mSessionKey; private final String mSessionKey;
@Nullable private IkeSession mSession; @Nullable private IkeSessionWrapper mSession;
@Nullable private IkeSessionConnectionInfo mIkeConnectionInfo; @Nullable private IkeSessionConnectionInfo mIkeConnectionInfo;
// mMobikeEnabled can only be updated after IKE AUTH is finished. // mMobikeEnabled can only be updated after IKE AUTH is finished.
@@ -2728,9 +2747,11 @@ public class Vpn {
*/ */
private int mRetryCount = 0; private int mRetryCount = 0;
IkeV2VpnRunner(@NonNull Ikev2VpnProfile profile) { IkeV2VpnRunner(
@NonNull Ikev2VpnProfile profile, @NonNull ScheduledThreadPoolExecutor executor) {
super(TAG); super(TAG);
mProfile = profile; mProfile = profile;
mExecutor = executor;
mIpSecManager = (IpSecManager) mContext.getSystemService(Context.IPSEC_SERVICE); mIpSecManager = (IpSecManager) mContext.getSystemService(Context.IPSEC_SERVICE);
mNetworkCallback = new VpnIkev2Utils.Ikev2VpnNetworkCallback(TAG, this, mExecutor); mNetworkCallback = new VpnIkev2Utils.Ikev2VpnNetworkCallback(TAG, this, mExecutor);
mSessionKey = UUID.randomUUID().toString(); mSessionKey = UUID.randomUUID().toString();
@@ -2743,7 +2764,7 @@ public class Vpn {
// To avoid hitting RejectedExecutionException upon shutdown of the mExecutor */ // To avoid hitting RejectedExecutionException upon shutdown of the mExecutor */
mExecutor.setRejectedExecutionHandler( mExecutor.setRejectedExecutionHandler(
(r, executor) -> { (r, exe) -> {
Log.d(TAG, "Runnable " + r + " rejected by the mExecutor"); Log.d(TAG, "Runnable " + r + " rejected by the mExecutor");
}); });
} }
@@ -2865,7 +2886,7 @@ public class Vpn {
// mActiveNetwork might have been updated after the setup was triggered. // mActiveNetwork might have been updated after the setup was triggered.
final Network network = mIkeConnectionInfo.getNetwork(); final Network network = mIkeConnectionInfo.getNetwork();
final NetworkAgent networkAgent; final VpnNetworkAgentWrapper networkAgent;
final LinkProperties lp; final LinkProperties lp;
synchronized (Vpn.this) { synchronized (Vpn.this) {
@@ -2884,7 +2905,6 @@ public class Vpn {
mConfig.dnsServers.addAll(dnsAddrStrings); mConfig.dnsServers.addAll(dnsAddrStrings);
mConfig.underlyingNetworks = new Network[] {network}; mConfig.underlyingNetworks = new Network[] {network};
mConfig.disallowedApplications = getAppExclusionList(mPackage); mConfig.disallowedApplications = getAppExclusionList(mPackage);
networkAgent = mNetworkAgent; networkAgent = mNetworkAgent;
@@ -2900,6 +2920,10 @@ public class Vpn {
} else { } else {
// Underlying networks also set in agentConnect() // Underlying networks also set in agentConnect()
networkAgent.setUnderlyingNetworks(Collections.singletonList(network)); networkAgent.setUnderlyingNetworks(Collections.singletonList(network));
mNetworkCapabilities =
new NetworkCapabilities.Builder(mNetworkCapabilities)
.setUnderlyingNetworks(Collections.singletonList(network))
.build();
} }
lp = makeLinkProperties(); // Accesses VPN instance fields; must be locked lp = makeLinkProperties(); // Accesses VPN instance fields; must be locked
@@ -4015,7 +4039,9 @@ public class Vpn {
case VpnProfile.TYPE_IKEV2_IPSEC_RSA: case VpnProfile.TYPE_IKEV2_IPSEC_RSA:
case VpnProfile.TYPE_IKEV2_FROM_IKE_TUN_CONN_PARAMS: case VpnProfile.TYPE_IKEV2_FROM_IKE_TUN_CONN_PARAMS:
mVpnRunner = mVpnRunner =
new IkeV2VpnRunner(Ikev2VpnProfile.fromVpnProfile(profile)); new IkeV2VpnRunner(
Ikev2VpnProfile.fromVpnProfile(profile),
mDeps.getScheduledThreadPoolExecutor());
mVpnRunner.start(); mVpnRunner.start();
break; break;
default: default:
@@ -4185,6 +4211,81 @@ public class Vpn {
return isCurrentIkev2VpnLocked(packageName) ? makeVpnProfileStateLocked() : null; return isCurrentIkev2VpnLocked(packageName) ? makeVpnProfileStateLocked() : null;
} }
/**
* Proxy to allow testing
*
* @hide
*/
@VisibleForTesting
public static class VpnNetworkAgentWrapper {
private final NetworkAgent mImpl;
/** Create an VpnNetworkAgentWrapper */
public VpnNetworkAgentWrapper(@NonNull NetworkAgent networkAgent) {
mImpl = networkAgent;
}
/** Inform ConnectivityService that this agent has now connected */
public void markConnected() {
mImpl.markConnected();
}
/** Register this network agent with ConnectivityService */
public void register() {
mImpl.register();
}
/** Unregister this network agent */
public void unregister() {
mImpl.unregister();
}
/** Update the LinkProperties */
public void sendLinkProperties(@NonNull LinkProperties lp) {
mImpl.sendLinkProperties(lp);
}
/** Update the NetworkCapabilities */
public void sendNetworkCapabilities(@NonNull NetworkCapabilities nc) {
mImpl.sendNetworkCapabilities(nc);
}
/** Set the underlying networks */
public void setUnderlyingNetworks(@NonNull List<Network> networks) {
mImpl.setUnderlyingNetworks(networks);
}
/** The Network associated with this agent */
public Network getNetwork() {
return mImpl.getNetwork();
}
}
/**
* Proxy to allow testing
*
* @hide
*/
@VisibleForTesting
public static class IkeSessionWrapper {
private final IkeSession mImpl;
/** Create an IkeSessionWrapper */
public IkeSessionWrapper(IkeSession session) {
mImpl = session;
}
/** Update the underlying network of the IKE Session */
public void setNetwork(@NonNull Network network) {
mImpl.setNetwork(network);
}
/** Forcibly terminate the IKE Session */
public void kill() {
mImpl.kill();
}
}
/** /**
* Proxy to allow testing * Proxy to allow testing
* *
@@ -4193,20 +4294,21 @@ public class Vpn {
@VisibleForTesting @VisibleForTesting
public static class Ikev2SessionCreator { public static class Ikev2SessionCreator {
/** Creates a IKE session */ /** Creates a IKE session */
public IkeSession createIkeSession( public IkeSessionWrapper createIkeSession(
@NonNull Context context, @NonNull Context context,
@NonNull IkeSessionParams ikeSessionParams, @NonNull IkeSessionParams ikeSessionParams,
@NonNull ChildSessionParams firstChildSessionParams, @NonNull ChildSessionParams firstChildSessionParams,
@NonNull Executor userCbExecutor, @NonNull Executor userCbExecutor,
@NonNull IkeSessionCallback ikeSessionCallback, @NonNull IkeSessionCallback ikeSessionCallback,
@NonNull ChildSessionCallback firstChildSessionCallback) { @NonNull ChildSessionCallback firstChildSessionCallback) {
return new IkeSession( return new IkeSessionWrapper(
new IkeSession(
context, context,
ikeSessionParams, ikeSessionParams,
firstChildSessionParams, firstChildSessionParams,
userCbExecutor, userCbExecutor,
ikeSessionCallback, ikeSessionCallback,
firstChildSessionCallback); firstChildSessionCallback));
} }
} }