Merge "Support ignoring validation failures after roam."
This commit is contained in:
@@ -168,4 +168,15 @@
|
|||||||
|
|
||||||
<!-- Regex of wired ethernet ifaces -->
|
<!-- Regex of wired ethernet ifaces -->
|
||||||
<string translatable="false" name="config_ethernet_iface_regex">eth\\d</string>
|
<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>
|
</resources>
|
||||||
|
|||||||
@@ -40,6 +40,7 @@
|
|||||||
<item type="string" name="config_ethernet_tcp_buffers"/>
|
<item type="string" name="config_ethernet_tcp_buffers"/>
|
||||||
<item type="array" name="config_ethernet_interfaces"/>
|
<item type="array" name="config_ethernet_interfaces"/>
|
||||||
<item type="string" name="config_ethernet_iface_regex"/>
|
<item type="string" name="config_ethernet_iface_regex"/>
|
||||||
|
<item type="integer" name="config_validationFailureAfterRoamIgnoreTimeMillis" />
|
||||||
</policy>
|
</policy>
|
||||||
</overlayable>
|
</overlayable>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -199,6 +199,7 @@ import android.net.resolv.aidl.Nat64PrefixEventParcel;
|
|||||||
import android.net.resolv.aidl.PrivateDnsValidationEventParcel;
|
import android.net.resolv.aidl.PrivateDnsValidationEventParcel;
|
||||||
import android.net.shared.PrivateDnsConfig;
|
import android.net.shared.PrivateDnsConfig;
|
||||||
import android.net.util.MultinetworkPolicyTracker;
|
import android.net.util.MultinetworkPolicyTracker;
|
||||||
|
import android.net.wifi.WifiInfo;
|
||||||
import android.os.BatteryStatsManager;
|
import android.os.BatteryStatsManager;
|
||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
import android.os.Build;
|
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_LINGER_DELAY_MS = 30_000;
|
||||||
private static final int DEFAULT_NASCENT_DELAY_MS = 5_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.
|
// The maximum number of network request allowed per uid before an exception is thrown.
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
static final int MAX_NETWORK_REQUESTS_PER_UID = 100;
|
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: {
|
case NetworkAgent.EVENT_NETWORK_CAPABILITIES_CHANGED: {
|
||||||
final NetworkCapabilities networkCapabilities = new NetworkCapabilities(
|
final NetworkCapabilities networkCapabilities = new NetworkCapabilities(
|
||||||
(NetworkCapabilities) arg.second);
|
(NetworkCapabilities) arg.second);
|
||||||
|
maybeUpdateWifiRoamTimestamp(nai, networkCapabilities);
|
||||||
processCapabilitiesFromAgent(nai, networkCapabilities);
|
processCapabilitiesFromAgent(nai, networkCapabilities);
|
||||||
updateCapabilities(nai.getCurrentScore(), nai, networkCapabilities);
|
updateCapabilities(nai.getCurrentScore(), nai, networkCapabilities);
|
||||||
break;
|
break;
|
||||||
@@ -3790,15 +3795,22 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
|
|
||||||
private void handleNetworkTested(
|
private void handleNetworkTested(
|
||||||
@NonNull NetworkAgentInfo nai, int testResult, @NonNull String redirectUrl) {
|
@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;
|
final boolean wasPartial = nai.partialConnectivity;
|
||||||
nai.partialConnectivity = ((testResult & NETWORK_VALIDATION_RESULT_PARTIAL) != 0);
|
nai.partialConnectivity = ((testResult & NETWORK_VALIDATION_RESULT_PARTIAL) != 0);
|
||||||
final boolean partialConnectivityChanged =
|
final boolean partialConnectivityChanged =
|
||||||
(wasPartial != nai.partialConnectivity);
|
(wasPartial != nai.partialConnectivity);
|
||||||
|
|
||||||
final boolean valid = ((testResult & NETWORK_VALIDATION_RESULT_VALID) != 0);
|
|
||||||
final boolean wasValidated = nai.lastValidated;
|
|
||||||
final boolean wasDefault = isDefaultNetwork(nai);
|
|
||||||
|
|
||||||
if (DBG) {
|
if (DBG) {
|
||||||
final String logMsg = !TextUtils.isEmpty(redirectUrl)
|
final String logMsg = !TextUtils.isEmpty(redirectUrl)
|
||||||
? " with redirect to " + redirectUrl
|
? " with redirect to " + redirectUrl
|
||||||
@@ -4197,6 +4209,23 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
return nai.created && !nai.destroyed;
|
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) {
|
private void handleNetworkAgentDisconnected(Message msg) {
|
||||||
NetworkAgentInfo nai = (NetworkAgentInfo) msg.obj;
|
NetworkAgentInfo nai = (NetworkAgentInfo) msg.obj;
|
||||||
disconnectAndDestroyNetwork(nai);
|
disconnectAndDestroyNetwork(nai);
|
||||||
@@ -9613,6 +9642,18 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
return ((VpnTransportInfo) ti).getType();
|
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.
|
* @param connectionInfo the connection to resolve.
|
||||||
* @return {@code uid} if the connection is found and the app has permission to observe it
|
* @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;
|
public boolean everConnected;
|
||||||
// Whether this network has been destroyed and is being kept temporarily until it is replaced.
|
// Whether this network has been destroyed and is being kept temporarily until it is replaced.
|
||||||
public boolean destroyed;
|
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
|
// 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.
|
// 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.assertTrue;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
import static org.junit.Assume.assumeTrue;
|
import static org.junit.Assume.assumeTrue;
|
||||||
|
import static org.junit.Assume.assumeFalse;
|
||||||
import static org.mockito.AdditionalMatchers.aryEq;
|
import static org.mockito.AdditionalMatchers.aryEq;
|
||||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||||
import static org.mockito.ArgumentMatchers.anyLong;
|
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.NetworkMonitorUtils;
|
||||||
import android.net.shared.PrivateDnsConfig;
|
import android.net.shared.PrivateDnsConfig;
|
||||||
import android.net.util.MultinetworkPolicyTracker;
|
import android.net.util.MultinetworkPolicyTracker;
|
||||||
|
import android.net.wifi.WifiInfo;
|
||||||
import android.os.BadParcelableException;
|
import android.os.BadParcelableException;
|
||||||
import android.os.BatteryStatsManager;
|
import android.os.BatteryStatsManager;
|
||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
@@ -15572,4 +15574,91 @@ public class ConnectivityServiceTest {
|
|||||||
|
|
||||||
assertNull(readHead.poll(TEST_CALLBACK_TIMEOUT_MS, it -> true));
|
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