Merge "Support ignoring validation failures after roam."
This commit is contained in:
@@ -168,4 +168,15 @@
|
||||
|
||||
<!-- Regex of wired ethernet ifaces -->
|
||||
<string translatable="false" name="config_ethernet_iface_regex">eth\\d</string>
|
||||
|
||||
<!-- Ignores Wi-Fi validation failures after roam.
|
||||
If validation fails on a Wi-Fi network after a roam to a new BSSID,
|
||||
assume that the roam temporarily disrupted network connectivity, and
|
||||
ignore all failures until this time has passed.
|
||||
NetworkMonitor will continue to attempt validation, and if it fails after this time has passed,
|
||||
the network will be marked unvalidated.
|
||||
|
||||
Only supported up to S. On T+, the Wi-Fi code should use destroyAndAwaitReplacement in order
|
||||
to ensure that apps see the network disconnect and reconnect. -->
|
||||
<integer translatable="false" name="config_validationFailureAfterRoamIgnoreTimeMillis">-1</integer>
|
||||
</resources>
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
<item type="string" name="config_ethernet_tcp_buffers"/>
|
||||
<item type="array" name="config_ethernet_interfaces"/>
|
||||
<item type="string" name="config_ethernet_iface_regex"/>
|
||||
<item type="integer" name="config_validationFailureAfterRoamIgnoreTimeMillis" />
|
||||
</policy>
|
||||
</overlayable>
|
||||
</resources>
|
||||
|
||||
@@ -199,6 +199,7 @@ import android.net.resolv.aidl.Nat64PrefixEventParcel;
|
||||
import android.net.resolv.aidl.PrivateDnsValidationEventParcel;
|
||||
import android.net.shared.PrivateDnsConfig;
|
||||
import android.net.util.MultinetworkPolicyTracker;
|
||||
import android.net.wifi.WifiInfo;
|
||||
import android.os.BatteryStatsManager;
|
||||
import android.os.Binder;
|
||||
import android.os.Build;
|
||||
@@ -348,6 +349,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
private static final int DEFAULT_LINGER_DELAY_MS = 30_000;
|
||||
private static final int DEFAULT_NASCENT_DELAY_MS = 5_000;
|
||||
|
||||
// The maximum value for the blocking validation result, in milliseconds.
|
||||
public static final int MAX_VALIDATION_FAILURE_BLOCKING_TIME_MS = 10000;
|
||||
|
||||
// The maximum number of network request allowed per uid before an exception is thrown.
|
||||
@VisibleForTesting
|
||||
static final int MAX_NETWORK_REQUESTS_PER_UID = 100;
|
||||
@@ -3543,6 +3547,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
case NetworkAgent.EVENT_NETWORK_CAPABILITIES_CHANGED: {
|
||||
final NetworkCapabilities networkCapabilities = new NetworkCapabilities(
|
||||
(NetworkCapabilities) arg.second);
|
||||
maybeUpdateWifiRoamTimestamp(nai, networkCapabilities);
|
||||
processCapabilitiesFromAgent(nai, networkCapabilities);
|
||||
updateCapabilities(nai.getCurrentScore(), nai, networkCapabilities);
|
||||
break;
|
||||
@@ -3790,15 +3795,22 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
|
||||
private void handleNetworkTested(
|
||||
@NonNull NetworkAgentInfo nai, int testResult, @NonNull String redirectUrl) {
|
||||
final boolean valid = ((testResult & NETWORK_VALIDATION_RESULT_VALID) != 0);
|
||||
if (!valid && shouldIgnoreValidationFailureAfterRoam(nai)) {
|
||||
// Assume the validation failure is due to a temporary failure after roaming
|
||||
// and ignore it. NetworkMonitor will continue to retry validation. If it
|
||||
// continues to fail after the block timeout expires, the network will be
|
||||
// marked unvalidated. If it succeeds, then validation state will not change.
|
||||
return;
|
||||
}
|
||||
|
||||
final boolean wasValidated = nai.lastValidated;
|
||||
final boolean wasDefault = isDefaultNetwork(nai);
|
||||
final boolean wasPartial = nai.partialConnectivity;
|
||||
nai.partialConnectivity = ((testResult & NETWORK_VALIDATION_RESULT_PARTIAL) != 0);
|
||||
final boolean partialConnectivityChanged =
|
||||
(wasPartial != nai.partialConnectivity);
|
||||
|
||||
final boolean valid = ((testResult & NETWORK_VALIDATION_RESULT_VALID) != 0);
|
||||
final boolean wasValidated = nai.lastValidated;
|
||||
final boolean wasDefault = isDefaultNetwork(nai);
|
||||
|
||||
if (DBG) {
|
||||
final String logMsg = !TextUtils.isEmpty(redirectUrl)
|
||||
? " with redirect to " + redirectUrl
|
||||
@@ -4197,6 +4209,23 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
return nai.created && !nai.destroyed;
|
||||
}
|
||||
|
||||
private boolean shouldIgnoreValidationFailureAfterRoam(NetworkAgentInfo nai) {
|
||||
// T+ devices should use destroyAndAwaitReplacement.
|
||||
if (SdkLevel.isAtLeastT()) return false;
|
||||
final long blockTimeOut = Long.valueOf(mResources.get().getInteger(
|
||||
R.integer.config_validationFailureAfterRoamIgnoreTimeMillis));
|
||||
if (blockTimeOut <= MAX_VALIDATION_FAILURE_BLOCKING_TIME_MS
|
||||
&& blockTimeOut >= 0) {
|
||||
final long currentTimeMs = SystemClock.elapsedRealtime();
|
||||
long timeSinceLastRoam = currentTimeMs - nai.lastRoamTimestamp;
|
||||
if (timeSinceLastRoam <= blockTimeOut) {
|
||||
log ("blocked because only " + timeSinceLastRoam + "ms after roam");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void handleNetworkAgentDisconnected(Message msg) {
|
||||
NetworkAgentInfo nai = (NetworkAgentInfo) msg.obj;
|
||||
disconnectAndDestroyNetwork(nai);
|
||||
@@ -9613,6 +9642,18 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
return ((VpnTransportInfo) ti).getType();
|
||||
}
|
||||
|
||||
private void maybeUpdateWifiRoamTimestamp(NetworkAgentInfo nai, NetworkCapabilities nc) {
|
||||
if (nai == null) return;
|
||||
final TransportInfo prevInfo = nai.networkCapabilities.getTransportInfo();
|
||||
final TransportInfo newInfo = nc.getTransportInfo();
|
||||
if (!(prevInfo instanceof WifiInfo) || !(newInfo instanceof WifiInfo)) {
|
||||
return;
|
||||
}
|
||||
if (!TextUtils.equals(((WifiInfo)prevInfo).getBSSID(), ((WifiInfo)newInfo).getBSSID())) {
|
||||
nai.lastRoamTimestamp = SystemClock.elapsedRealtime();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param connectionInfo the connection to resolve.
|
||||
* @return {@code uid} if the connection is found and the app has permission to observe it
|
||||
|
||||
@@ -192,6 +192,8 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo>, NetworkRa
|
||||
public boolean everConnected;
|
||||
// Whether this network has been destroyed and is being kept temporarily until it is replaced.
|
||||
public boolean destroyed;
|
||||
// To check how long it has been since last roam.
|
||||
public long lastRoamTimestamp;
|
||||
|
||||
// Set to true if this Network successfully passed validation or if it did not satisfy the
|
||||
// default NetworkRequest in which case validation will not be attempted.
|
||||
|
||||
@@ -160,6 +160,7 @@ import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
import static org.junit.Assume.assumeFalse;
|
||||
import static org.mockito.AdditionalMatchers.aryEq;
|
||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
@@ -283,6 +284,7 @@ import android.net.resolv.aidl.PrivateDnsValidationEventParcel;
|
||||
import android.net.shared.NetworkMonitorUtils;
|
||||
import android.net.shared.PrivateDnsConfig;
|
||||
import android.net.util.MultinetworkPolicyTracker;
|
||||
import android.net.wifi.WifiInfo;
|
||||
import android.os.BadParcelableException;
|
||||
import android.os.BatteryStatsManager;
|
||||
import android.os.Binder;
|
||||
@@ -15572,4 +15574,91 @@ public class ConnectivityServiceTest {
|
||||
|
||||
assertNull(readHead.poll(TEST_CALLBACK_TIMEOUT_MS, it -> true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIgnoreValidationAfterRoamDisabled() throws Exception {
|
||||
assumeFalse(SdkLevel.isAtLeastT());
|
||||
// testIgnoreValidationAfterRoam off
|
||||
doReturn(-1).when(mResources)
|
||||
.getInteger(R.integer.config_validationFailureAfterRoamIgnoreTimeMillis);
|
||||
|
||||
mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
|
||||
mCellNetworkAgent.connect(true);
|
||||
NetworkCapabilities wifiNc1 = new NetworkCapabilities()
|
||||
.addTransportType(TRANSPORT_WIFI)
|
||||
.setTransportInfo(new WifiInfo.Builder().setBssid("AA:AA:AA:AA:AA:AA").build());
|
||||
NetworkCapabilities wifiNc2 = new NetworkCapabilities()
|
||||
.addTransportType(TRANSPORT_WIFI)
|
||||
.setTransportInfo(new WifiInfo.Builder().setBssid("BB:BB:BB:BB:BB:BB").build());
|
||||
final LinkProperties wifiLp = new LinkProperties();
|
||||
wifiLp.setInterfaceName(WIFI_IFNAME);
|
||||
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, wifiLp, wifiNc1);
|
||||
mWiFiNetworkAgent.connect(true);
|
||||
|
||||
// The default network will be switching to Wi-Fi Network.
|
||||
final TestNetworkCallback wifiNetworkCallback = new TestNetworkCallback();
|
||||
final NetworkRequest wifiRequest = new NetworkRequest.Builder()
|
||||
.addTransportType(TRANSPORT_WIFI).build();
|
||||
mCm.registerNetworkCallback(wifiRequest, wifiNetworkCallback);
|
||||
wifiNetworkCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
|
||||
registerDefaultNetworkCallbacks();
|
||||
mDefaultNetworkCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
|
||||
|
||||
// Wi-Fi roaming from wifiNc1 to wifiNc2.
|
||||
mWiFiNetworkAgent.setNetworkCapabilities(wifiNc2, true);
|
||||
mWiFiNetworkAgent.setNetworkInvalid(false);
|
||||
mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), false);
|
||||
mDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIgnoreValidationAfterRoamEnabled() throws Exception {
|
||||
assumeFalse(SdkLevel.isAtLeastT());
|
||||
// testIgnoreValidationAfterRoam on
|
||||
doReturn(5000).when(mResources)
|
||||
.getInteger(R.integer.config_validationFailureAfterRoamIgnoreTimeMillis);
|
||||
|
||||
mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
|
||||
mCellNetworkAgent.connect(true);
|
||||
NetworkCapabilities wifiNc1 = new NetworkCapabilities()
|
||||
.addTransportType(TRANSPORT_WIFI)
|
||||
.setTransportInfo(new WifiInfo.Builder().setBssid("AA:AA:AA:AA:AA:AA").build());
|
||||
NetworkCapabilities wifiNc2 = new NetworkCapabilities()
|
||||
.addTransportType(TRANSPORT_WIFI)
|
||||
.setTransportInfo(new WifiInfo.Builder().setBssid("BB:BB:BB:BB:BB:BB").build());
|
||||
final LinkProperties wifiLp = new LinkProperties();
|
||||
wifiLp.setInterfaceName(WIFI_IFNAME);
|
||||
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, wifiLp, wifiNc1);
|
||||
mWiFiNetworkAgent.connect(true);
|
||||
|
||||
// The default network will be switching to Wi-Fi Network.
|
||||
final TestNetworkCallback wifiNetworkCallback = new TestNetworkCallback();
|
||||
final NetworkRequest wifiRequest = new NetworkRequest.Builder()
|
||||
.addTransportType(TRANSPORT_WIFI).build();
|
||||
mCm.registerNetworkCallback(wifiRequest, wifiNetworkCallback);
|
||||
wifiNetworkCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
|
||||
registerDefaultNetworkCallbacks();
|
||||
mDefaultNetworkCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
|
||||
|
||||
// Wi-Fi roaming from wifiNc1 to wifiNc2.
|
||||
mWiFiNetworkAgent.setNetworkCapabilities(wifiNc2, true);
|
||||
mWiFiNetworkAgent.setNetworkInvalid(false);
|
||||
mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), false);
|
||||
|
||||
// Network validation failed, but the result will be ignored.
|
||||
assertTrue(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
|
||||
NET_CAPABILITY_VALIDATED));
|
||||
mWiFiNetworkAgent.setNetworkValid(false);
|
||||
|
||||
// Behavior of after config_validationFailureAfterRoamIgnoreTimeMillis
|
||||
ConditionVariable waitForValidationBlock = new ConditionVariable();
|
||||
doReturn(50).when(mResources)
|
||||
.getInteger(R.integer.config_validationFailureAfterRoamIgnoreTimeMillis);
|
||||
// Wi-Fi roaming from wifiNc2 to wifiNc1.
|
||||
mWiFiNetworkAgent.setNetworkCapabilities(wifiNc1, true);
|
||||
mWiFiNetworkAgent.setNetworkInvalid(false);
|
||||
waitForValidationBlock.block(150);
|
||||
mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), false);
|
||||
mDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user