Merge changes Ib3cbdbfa,Ic98e3906 into tm-qpr-dev
* changes: Minor cleanups in VPN Make VPN more testable and update NC during network change
This commit is contained in:
committed by
Android (Google) Code Review
commit
32013bb060
@@ -498,6 +498,29 @@ 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 newScheduledThreadPoolExecutor() {
|
||||||
|
return new ScheduledThreadPoolExecutor(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get a NetworkAgent instance */
|
||||||
|
public NetworkAgent newNetworkAgent(
|
||||||
|
@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 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,
|
||||||
@@ -1474,15 +1497,10 @@ 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.newNetworkAgent(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();
|
||||||
@@ -2692,11 +2710,10 @@ 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<?> mScheduledHandleNetworkLostFuture;
|
||||||
@Nullable private ScheduledFuture<?> mScheduledHandleRetryIkeSessionTimeout;
|
@Nullable private ScheduledFuture<?> mScheduledHandleRetryIkeSessionFuture;
|
||||||
|
|
||||||
/** Signal to ensure shutdown is honored even if a new Network is connected. */
|
/** Signal to ensure shutdown is honored even if a new Network is connected. */
|
||||||
private boolean mIsRunning = true;
|
private boolean mIsRunning = true;
|
||||||
@@ -2714,7 +2731,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 +2745,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 +2762,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");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -2884,7 +2903,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 +2918,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
|
||||||
@@ -2933,6 +2955,8 @@ public class Vpn {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
mTunnelIface.setUnderlyingNetwork(mIkeConnectionInfo.getNetwork());
|
||||||
|
|
||||||
// Transforms do not need to be persisted; the IkeSession will keep
|
// Transforms do not need to be persisted; the IkeSession will keep
|
||||||
// them alive for us
|
// them alive for us
|
||||||
mIpSecManager.applyTunnelModeTransform(mTunnelIface, direction, transform);
|
mIpSecManager.applyTunnelModeTransform(mTunnelIface, direction, transform);
|
||||||
@@ -3114,13 +3138,13 @@ public class Vpn {
|
|||||||
// If the default network is lost during the retry delay, the mActiveNetwork will be
|
// If the default network is lost during the retry delay, the mActiveNetwork will be
|
||||||
// null, and the new IKE session won't be established until there is a new default
|
// null, and the new IKE session won't be established until there is a new default
|
||||||
// network bringing up.
|
// network bringing up.
|
||||||
mScheduledHandleRetryIkeSessionTimeout =
|
mScheduledHandleRetryIkeSessionFuture =
|
||||||
mExecutor.schedule(() -> {
|
mExecutor.schedule(() -> {
|
||||||
startOrMigrateIkeSession(mActiveNetwork);
|
startOrMigrateIkeSession(mActiveNetwork);
|
||||||
|
|
||||||
// Reset mScheduledHandleRetryIkeSessionTimeout since it's already run on
|
// Reset mScheduledHandleRetryIkeSessionFuture since it's already run on
|
||||||
// executor thread.
|
// executor thread.
|
||||||
mScheduledHandleRetryIkeSessionTimeout = null;
|
mScheduledHandleRetryIkeSessionFuture = null;
|
||||||
}, retryDelay, TimeUnit.SECONDS);
|
}, retryDelay, TimeUnit.SECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3163,12 +3187,10 @@ public class Vpn {
|
|||||||
mActiveNetwork = null;
|
mActiveNetwork = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mScheduledHandleNetworkLostTimeout != null
|
if (mScheduledHandleNetworkLostFuture != null) {
|
||||||
&& !mScheduledHandleNetworkLostTimeout.isCancelled()
|
|
||||||
&& !mScheduledHandleNetworkLostTimeout.isDone()) {
|
|
||||||
final IllegalStateException exception =
|
final IllegalStateException exception =
|
||||||
new IllegalStateException(
|
new IllegalStateException(
|
||||||
"Found a pending mScheduledHandleNetworkLostTimeout");
|
"Found a pending mScheduledHandleNetworkLostFuture");
|
||||||
Log.i(
|
Log.i(
|
||||||
TAG,
|
TAG,
|
||||||
"Unexpected error in onDefaultNetworkLost. Tear down session",
|
"Unexpected error in onDefaultNetworkLost. Tear down session",
|
||||||
@@ -3185,13 +3207,26 @@ public class Vpn {
|
|||||||
+ " on session with token "
|
+ " on session with token "
|
||||||
+ mCurrentToken);
|
+ mCurrentToken);
|
||||||
|
|
||||||
|
final int token = mCurrentToken;
|
||||||
// Delay the teardown in case a new network will be available soon. For example,
|
// Delay the teardown in case a new network will be available soon. For example,
|
||||||
// during handover between two WiFi networks, Android will disconnect from the
|
// during handover between two WiFi networks, Android will disconnect from the
|
||||||
// first WiFi and then connects to the second WiFi.
|
// first WiFi and then connects to the second WiFi.
|
||||||
mScheduledHandleNetworkLostTimeout =
|
mScheduledHandleNetworkLostFuture =
|
||||||
mExecutor.schedule(
|
mExecutor.schedule(
|
||||||
() -> {
|
() -> {
|
||||||
|
if (isActiveToken(token)) {
|
||||||
handleSessionLost(null, network);
|
handleSessionLost(null, network);
|
||||||
|
} else {
|
||||||
|
Log.d(
|
||||||
|
TAG,
|
||||||
|
"Scheduled handleSessionLost fired for "
|
||||||
|
+ "obsolete token "
|
||||||
|
+ token);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset mScheduledHandleNetworkLostFuture since it's
|
||||||
|
// already run on executor thread.
|
||||||
|
mScheduledHandleNetworkLostFuture = null;
|
||||||
},
|
},
|
||||||
NETWORK_LOST_TIMEOUT_MS,
|
NETWORK_LOST_TIMEOUT_MS,
|
||||||
TimeUnit.MILLISECONDS);
|
TimeUnit.MILLISECONDS);
|
||||||
@@ -3202,28 +3237,26 @@ public class Vpn {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void cancelHandleNetworkLostTimeout() {
|
private void cancelHandleNetworkLostTimeout() {
|
||||||
if (mScheduledHandleNetworkLostTimeout != null
|
if (mScheduledHandleNetworkLostFuture != null) {
|
||||||
&& !mScheduledHandleNetworkLostTimeout.isDone()) {
|
|
||||||
// It does not matter what to put in #cancel(boolean), because it is impossible
|
// It does not matter what to put in #cancel(boolean), because it is impossible
|
||||||
// that the task tracked by mScheduledHandleNetworkLostTimeout is
|
// that the task tracked by mScheduledHandleNetworkLostFuture is
|
||||||
// in-progress since both that task and onDefaultNetworkChanged are submitted to
|
// in-progress since both that task and onDefaultNetworkChanged are submitted to
|
||||||
// mExecutor who has only one thread.
|
// mExecutor who has only one thread.
|
||||||
Log.d(TAG, "Cancel the task for handling network lost timeout");
|
Log.d(TAG, "Cancel the task for handling network lost timeout");
|
||||||
mScheduledHandleNetworkLostTimeout.cancel(false /* mayInterruptIfRunning */);
|
mScheduledHandleNetworkLostFuture.cancel(false /* mayInterruptIfRunning */);
|
||||||
mScheduledHandleNetworkLostTimeout = null;
|
mScheduledHandleNetworkLostFuture = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void cancelRetryNewIkeSessionFuture() {
|
private void cancelRetryNewIkeSessionFuture() {
|
||||||
if (mScheduledHandleRetryIkeSessionTimeout != null
|
if (mScheduledHandleRetryIkeSessionFuture != null) {
|
||||||
&& !mScheduledHandleRetryIkeSessionTimeout.isDone()) {
|
|
||||||
// It does not matter what to put in #cancel(boolean), because it is impossible
|
// It does not matter what to put in #cancel(boolean), because it is impossible
|
||||||
// that the task tracked by mScheduledHandleRetryIkeSessionTimeout is
|
// that the task tracked by mScheduledHandleRetryIkeSessionFuture is
|
||||||
// in-progress since both that task and onDefaultNetworkChanged are submitted to
|
// in-progress since both that task and onDefaultNetworkChanged are submitted to
|
||||||
// mExecutor who has only one thread.
|
// mExecutor who has only one thread.
|
||||||
Log.d(TAG, "Cancel the task for handling new ike session timeout");
|
Log.d(TAG, "Cancel the task for handling new ike session timeout");
|
||||||
mScheduledHandleRetryIkeSessionTimeout.cancel(false /* mayInterruptIfRunning */);
|
mScheduledHandleRetryIkeSessionFuture.cancel(false /* mayInterruptIfRunning */);
|
||||||
mScheduledHandleRetryIkeSessionTimeout = null;
|
mScheduledHandleRetryIkeSessionFuture = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3263,7 +3296,7 @@ public class Vpn {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void handleSessionLost(@Nullable Exception exception, @Nullable Network network) {
|
private void handleSessionLost(@Nullable Exception exception, @Nullable Network network) {
|
||||||
// Cancel mScheduledHandleNetworkLostTimeout if the session it is going to terminate is
|
// Cancel mScheduledHandleNetworkLostFuture if the session it is going to terminate is
|
||||||
// already terminated due to other failures.
|
// already terminated due to other failures.
|
||||||
cancelHandleNetworkLostTimeout();
|
cancelHandleNetworkLostTimeout();
|
||||||
|
|
||||||
@@ -4015,7 +4048,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.newScheduledThreadPoolExecutor());
|
||||||
mVpnRunner.start();
|
mVpnRunner.start();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -4185,6 +4220,31 @@ public class Vpn {
|
|||||||
return isCurrentIkev2VpnLocked(packageName) ? makeVpnProfileStateLocked() : null;
|
return isCurrentIkev2VpnLocked(packageName) ? makeVpnProfileStateLocked() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 +4253,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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user