Merge "Fix a bug where a spurious capabilities callback is sent."
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index fea3245..74eced7 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -169,6 +169,7 @@
NET_CAPABILITY_OEM_PAID,
NET_CAPABILITY_MCX,
NET_CAPABILITY_PARTIAL_CONNECTIVITY,
+ NET_CAPABILITY_TEMPORARILY_NOT_METERED,
})
public @interface NetCapability { }
@@ -336,8 +337,16 @@
@SystemApi
public static final int NET_CAPABILITY_PARTIAL_CONNECTIVITY = 24;
+ /**
+ * This capability will be set for networks that are generally metered, but are currently
+ * unmetered, e.g., because the user is in a particular area. This capability can be changed at
+ * any time. When it is removed, applications are responsible for stopping any data transfer
+ * that should not occur on a metered network.
+ */
+ public static final int NET_CAPABILITY_TEMPORARILY_NOT_METERED = 25;
+
private static final int MIN_NET_CAPABILITY = NET_CAPABILITY_MMS;
- private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_PARTIAL_CONNECTIVITY;
+ private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_TEMPORARILY_NOT_METERED;
/**
* Network capabilities that are expected to be mutable, i.e., can change while a particular
@@ -353,7 +362,8 @@
| (1 << NET_CAPABILITY_FOREGROUND)
| (1 << NET_CAPABILITY_NOT_CONGESTED)
| (1 << NET_CAPABILITY_NOT_SUSPENDED)
- | (1 << NET_CAPABILITY_PARTIAL_CONNECTIVITY);
+ | (1 << NET_CAPABILITY_PARTIAL_CONNECTIVITY
+ | (1 << NET_CAPABILITY_TEMPORARILY_NOT_METERED));
/**
* Network capabilities that are not allowed in NetworkRequests. This exists because the
@@ -424,6 +434,7 @@
*/
private static final long TEST_NETWORKS_ALLOWED_CAPABILITIES =
(1 << NET_CAPABILITY_NOT_METERED)
+ | (1 << NET_CAPABILITY_TEMPORARILY_NOT_METERED)
| (1 << NET_CAPABILITY_NOT_RESTRICTED)
| (1 << NET_CAPABILITY_NOT_VPN)
| (1 << NET_CAPABILITY_NOT_ROAMING)
@@ -1866,6 +1877,7 @@
case NET_CAPABILITY_OEM_PAID: return "OEM_PAID";
case NET_CAPABILITY_MCX: return "MCX";
case NET_CAPABILITY_PARTIAL_CONNECTIVITY: return "PARTIAL_CONNECTIVITY";
+ case NET_CAPABILITY_TEMPORARILY_NOT_METERED: return "TEMPORARILY_NOT_METERED";
default: return Integer.toString(capability);
}
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 7c6dfff..08aab2a 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -18,6 +18,14 @@
import static android.Manifest.permission.RECEIVE_DATA_ACTIVITY_CHANGE;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.KEY_NETWORK_PROBES_ATTEMPTED_BITMASK;
+import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.KEY_NETWORK_PROBES_SUCCEEDED_BITMASK;
+import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.KEY_NETWORK_VALIDATION_RESULT;
+import static android.net.ConnectivityDiagnosticsManager.DataStallReport.DETECTION_METHOD_DNS_EVENTS;
+import static android.net.ConnectivityDiagnosticsManager.DataStallReport.DETECTION_METHOD_TCP_METRICS;
+import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_DNS_CONSECUTIVE_TIMEOUTS;
+import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS;
+import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_TCP_PACKET_FAIL_RATE;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.NETID_UNSET;
import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
@@ -72,6 +80,7 @@
import android.net.ConnectivityDiagnosticsManager.ConnectivityReport;
import android.net.ConnectivityDiagnosticsManager.DataStallReport;
import android.net.ConnectivityManager;
+import android.net.DataStallReportParcelable;
import android.net.ICaptivePortal;
import android.net.IConnectivityDiagnosticsCallback;
import android.net.IConnectivityManager;
@@ -108,6 +117,7 @@
import android.net.NetworkStack;
import android.net.NetworkStackClient;
import android.net.NetworkState;
+import android.net.NetworkTestResultParcelable;
import android.net.NetworkUtils;
import android.net.NetworkWatchlistManager;
import android.net.PrivateDnsConfigParcel;
@@ -2812,14 +2822,6 @@
handleNetworkTested(nai, results.mTestResult,
(results.mRedirectUrl == null) ? "" : results.mRedirectUrl);
-
- // Invoke ConnectivityReport generation for this Network test event.
- final Message m =
- mConnectivityDiagnosticsHandler.obtainMessage(
- ConnectivityDiagnosticsHandler.EVENT_NETWORK_TESTED,
- new ConnectivityReportEvent(results.mTimestampMillis, nai));
- m.setData(msg.getData());
- mConnectivityDiagnosticsHandler.sendMessage(m);
break;
}
case EVENT_PROVISIONING_NOTIFICATION: {
@@ -2998,23 +3000,36 @@
@Override
public void notifyNetworkTested(int testResult, @Nullable String redirectUrl) {
- notifyNetworkTestedWithExtras(testResult, redirectUrl, SystemClock.elapsedRealtime(),
- PersistableBundle.EMPTY);
+ // Legacy version of notifyNetworkTestedWithExtras.
+ // Would only be called if the system has a NetworkStack module older than the
+ // framework, which does not happen in practice.
+ Slog.wtf(TAG, "Deprecated notifyNetworkTested called: no action taken");
}
@Override
- public void notifyNetworkTestedWithExtras(
- int testResult,
- @Nullable String redirectUrl,
- long timestampMillis,
- @NonNull PersistableBundle extras) {
- final Message msg =
- mTrackerHandler.obtainMessage(
- EVENT_NETWORK_TESTED,
- new NetworkTestedResults(
- mNetId, testResult, timestampMillis, redirectUrl));
- msg.setData(new Bundle(extras));
+ public void notifyNetworkTestedWithExtras(NetworkTestResultParcelable p) {
+ // Notify mTrackerHandler and mConnectivityDiagnosticsHandler of the event. Both use
+ // the same looper so messages will be processed in sequence.
+ final Message msg = mTrackerHandler.obtainMessage(
+ EVENT_NETWORK_TESTED,
+ new NetworkTestedResults(
+ mNetId, p.result, p.timestampMillis, p.redirectUrl));
mTrackerHandler.sendMessage(msg);
+
+ // Invoke ConnectivityReport generation for this Network test event.
+ final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(mNetId);
+ if (nai == null) return;
+ final Message m = mConnectivityDiagnosticsHandler.obtainMessage(
+ ConnectivityDiagnosticsHandler.EVENT_NETWORK_TESTED,
+ new ConnectivityReportEvent(p.timestampMillis, nai));
+
+ final PersistableBundle extras = new PersistableBundle();
+ extras.putInt(KEY_NETWORK_VALIDATION_RESULT, p.result);
+ extras.putInt(KEY_NETWORK_PROBES_SUCCEEDED_BITMASK, p.probesSucceeded);
+ extras.putInt(KEY_NETWORK_PROBES_ATTEMPTED_BITMASK, p.probesAttempted);
+
+ m.setData(new Bundle(extras));
+ mConnectivityDiagnosticsHandler.sendMessage(m);
}
@Override
@@ -3063,12 +3078,25 @@
}
@Override
- public void notifyDataStallSuspected(
- long timestampMillis, int detectionMethod, PersistableBundle extras) {
- final Message msg =
- mConnectivityDiagnosticsHandler.obtainMessage(
- ConnectivityDiagnosticsHandler.EVENT_DATA_STALL_SUSPECTED,
- detectionMethod, mNetId, timestampMillis);
+ public void notifyDataStallSuspected(DataStallReportParcelable p) {
+ final Message msg = mConnectivityDiagnosticsHandler.obtainMessage(
+ ConnectivityDiagnosticsHandler.EVENT_DATA_STALL_SUSPECTED,
+ p.detectionMethod, mNetId, p.timestampMillis);
+
+ final PersistableBundle extras = new PersistableBundle();
+ switch (p.detectionMethod) {
+ case DETECTION_METHOD_DNS_EVENTS:
+ extras.putInt(KEY_DNS_CONSECUTIVE_TIMEOUTS, p.dnsConsecutiveTimeouts);
+ break;
+ case DETECTION_METHOD_TCP_METRICS:
+ extras.putInt(KEY_TCP_PACKET_FAIL_RATE, p.tcpPacketFailRate);
+ extras.putInt(KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS,
+ p.tcpMetricsCollectionPeriodMillis);
+ break;
+ default:
+ log("Unknown data stall detection method, ignoring: " + p.detectionMethod);
+ return;
+ }
msg.setData(new Bundle(extras));
// NetworkStateTrackerHandler currently doesn't take any actions based on data
diff --git a/tests/net/common/java/android/net/MatchAllNetworkSpecifierTest.kt b/tests/net/common/java/android/net/MatchAllNetworkSpecifierTest.kt
index ef15b66..a50f046 100644
--- a/tests/net/common/java/android/net/MatchAllNetworkSpecifierTest.kt
+++ b/tests/net/common/java/android/net/MatchAllNetworkSpecifierTest.kt
@@ -39,12 +39,12 @@
}
@Test(expected = IllegalStateException::class)
- fun testSatisfiedBy() {
+ fun testCanBeSatisfiedBy() {
val specifier = MatchAllNetworkSpecifier()
val discoverySession = Mockito.mock(DiscoverySession::class.java)
val peerHandle = Mockito.mock(PeerHandle::class.java)
val wifiAwareNetworkSpecifier = WifiAwareNetworkSpecifier.Builder(discoverySession,
peerHandle).build()
- specifier.satisfiedBy(wifiAwareNetworkSpecifier)
+ specifier.canBeSatisfiedBy(wifiAwareNetworkSpecifier)
}
}
diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt b/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt
index eec3cdb..8c2de40 100644
--- a/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt
+++ b/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt
@@ -52,7 +52,7 @@
doReturn(mock(IBinder::class.java)).`when`(it).getSystemService(Context.NETD_SERVICE)
}
- private class TestPermissionChecker : NetworkStackConnector.PermissionChecker() {
+ private class TestPermissionChecker : NetworkStackService.PermissionChecker() {
override fun enforceNetworkStackCallingPermission() = Unit
}
@@ -62,8 +62,8 @@
override fun sendNetworkConditionsBroadcast(context: Context, broadcast: Intent) = Unit
}
- private inner class TestNetworkStackConnector(context: Context) :
- NetworkStackConnector(context, TestPermissionChecker()) {
+ private inner class TestNetworkStackConnector(context: Context) : NetworkStackConnector(
+ context, TestPermissionChecker(), NetworkStackService.Dependencies()) {
private val network = Network(TEST_NETID)
private val privateDnsBypassNetwork = TestNetwork(TEST_NETID)
diff --git a/tests/net/java/android/net/Ikev2VpnProfileTest.java b/tests/net/java/android/net/Ikev2VpnProfileTest.java
index 2273bc6..ada5494 100644
--- a/tests/net/java/android/net/Ikev2VpnProfileTest.java
+++ b/tests/net/java/android/net/Ikev2VpnProfileTest.java
@@ -40,7 +40,10 @@
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Date;
+import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.security.auth.x500.X500Principal;
@@ -106,6 +109,7 @@
assertTrue(profile.isBypassable());
assertTrue(profile.isMetered());
assertEquals(TEST_MTU, profile.getMaxMtu());
+ assertEquals(Ikev2VpnProfile.DEFAULT_ALGORITHMS, profile.getAllowedAlgorithms());
}
@Test
@@ -160,6 +164,78 @@
}
@Test
+ public void testBuildWithAllowedAlgorithmsAead() throws Exception {
+ final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
+ builder.setAuthPsk(PSK_BYTES);
+
+ List<String> allowedAlgorithms = Arrays.asList(IpSecAlgorithm.AUTH_CRYPT_AES_GCM);
+ builder.setAllowedAlgorithms(allowedAlgorithms);
+
+ final Ikev2VpnProfile profile = builder.build();
+ assertEquals(allowedAlgorithms, profile.getAllowedAlgorithms());
+ }
+
+ @Test
+ public void testBuildWithAllowedAlgorithmsNormal() throws Exception {
+ final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
+ builder.setAuthPsk(PSK_BYTES);
+
+ List<String> allowedAlgorithms =
+ Arrays.asList(IpSecAlgorithm.AUTH_HMAC_SHA512, IpSecAlgorithm.CRYPT_AES_CBC);
+ builder.setAllowedAlgorithms(allowedAlgorithms);
+
+ final Ikev2VpnProfile profile = builder.build();
+ assertEquals(allowedAlgorithms, profile.getAllowedAlgorithms());
+ }
+
+ @Test
+ public void testSetAllowedAlgorithmsEmptyList() throws Exception {
+ final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
+
+ try {
+ builder.setAllowedAlgorithms(new ArrayList<>());
+ fail("Expected exception due to no valid algorithm set");
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ @Test
+ public void testSetAllowedAlgorithmsInvalidList() throws Exception {
+ final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
+ List<String> allowedAlgorithms = new ArrayList<>();
+
+ try {
+ builder.setAllowedAlgorithms(Arrays.asList(IpSecAlgorithm.AUTH_HMAC_SHA256));
+ fail("Expected exception due to missing encryption");
+ } catch (IllegalArgumentException expected) {
+ }
+
+ try {
+ builder.setAllowedAlgorithms(Arrays.asList(IpSecAlgorithm.CRYPT_AES_CBC));
+ fail("Expected exception due to missing authentication");
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ @Test
+ public void testSetAllowedAlgorithmsInsecureAlgorithm() throws Exception {
+ final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
+ List<String> allowedAlgorithms = new ArrayList<>();
+
+ try {
+ builder.setAllowedAlgorithms(Arrays.asList(IpSecAlgorithm.AUTH_HMAC_MD5));
+ fail("Expected exception due to insecure algorithm");
+ } catch (IllegalArgumentException expected) {
+ }
+
+ try {
+ builder.setAllowedAlgorithms(Arrays.asList(IpSecAlgorithm.AUTH_HMAC_SHA1));
+ fail("Expected exception due to insecure algorithm");
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ @Test
public void testBuildNoAuthMethodSet() throws Exception {
final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 75152e6..bef682b 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -144,6 +144,7 @@
import android.net.ConnectivityManager.PacketKeepaliveCallback;
import android.net.ConnectivityManager.TooManyRequestsException;
import android.net.ConnectivityThread;
+import android.net.DataStallReportParcelable;
import android.net.IConnectivityDiagnosticsCallback;
import android.net.IDnsResolver;
import android.net.IIpConnectivityMetrics;
@@ -170,6 +171,7 @@
import android.net.NetworkStack;
import android.net.NetworkStackClient;
import android.net.NetworkState;
+import android.net.NetworkTestResultParcelable;
import android.net.NetworkUtils;
import android.net.ProxyInfo;
import android.net.ResolverParamsParcel;
@@ -196,7 +198,6 @@
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
-import android.os.PersistableBundle;
import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
@@ -580,14 +581,6 @@
}
private class TestNetworkAgentWrapper extends NetworkAgentWrapper {
- private static final int VALIDATION_RESULT_BASE = NETWORK_VALIDATION_PROBE_DNS
- | NETWORK_VALIDATION_PROBE_HTTP
- | NETWORK_VALIDATION_PROBE_HTTPS;
- private static final int VALIDATION_RESULT_VALID = VALIDATION_RESULT_BASE
- | NETWORK_VALIDATION_RESULT_VALID;
- private static final int VALIDATION_RESULT_PARTIAL = VALIDATION_RESULT_BASE
- | NETWORK_VALIDATION_PROBE_FALLBACK
- | NETWORK_VALIDATION_RESULT_PARTIAL;
private static final int VALIDATION_RESULT_INVALID = 0;
private static final long DATA_STALL_TIMESTAMP = 10L;
@@ -595,12 +588,10 @@
private INetworkMonitor mNetworkMonitor;
private INetworkMonitorCallbacks mNmCallbacks;
- private int mNmValidationResult = VALIDATION_RESULT_BASE;
+ private int mNmValidationResult = VALIDATION_RESULT_INVALID;
private int mProbesCompleted;
private int mProbesSucceeded;
private String mNmValidationRedirectUrl = null;
- private PersistableBundle mValidationExtras = PersistableBundle.EMPTY;
- private PersistableBundle mDataStallExtras = PersistableBundle.EMPTY;
private boolean mNmProvNotificationRequested = false;
private final ConditionVariable mNetworkStatusReceived = new ConditionVariable();
@@ -668,8 +659,13 @@
}
mNmCallbacks.notifyProbeStatusChanged(mProbesCompleted, mProbesSucceeded);
- mNmCallbacks.notifyNetworkTestedWithExtras(
- mNmValidationResult, mNmValidationRedirectUrl, TIMESTAMP, mValidationExtras);
+ final NetworkTestResultParcelable p = new NetworkTestResultParcelable();
+ p.result = mNmValidationResult;
+ p.probesAttempted = mProbesCompleted;
+ p.probesSucceeded = mProbesSucceeded;
+ p.redirectUrl = mNmValidationRedirectUrl;
+ p.timestampMillis = TIMESTAMP;
+ mNmCallbacks.notifyNetworkTestedWithExtras(p);
if (mNmValidationRedirectUrl != null) {
mNmCallbacks.showProvisioningNotification(
@@ -751,9 +747,9 @@
}
void setNetworkValid(boolean isStrictMode) {
- mNmValidationResult = VALIDATION_RESULT_VALID;
+ mNmValidationResult = NETWORK_VALIDATION_RESULT_VALID;
mNmValidationRedirectUrl = null;
- int probesSucceeded = VALIDATION_RESULT_BASE & ~NETWORK_VALIDATION_PROBE_HTTP;
+ int probesSucceeded = NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTPS;
if (isStrictMode) {
probesSucceeded |= NETWORK_VALIDATION_PROBE_PRIVDNS;
}
@@ -765,8 +761,9 @@
void setNetworkInvalid(boolean isStrictMode) {
mNmValidationResult = VALIDATION_RESULT_INVALID;
mNmValidationRedirectUrl = null;
- int probesCompleted = VALIDATION_RESULT_BASE;
- int probesSucceeded = VALIDATION_RESULT_INVALID;
+ int probesCompleted = NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTPS
+ | NETWORK_VALIDATION_PROBE_HTTP;
+ int probesSucceeded = 0;
// If the isStrictMode is true, it means the network is invalid when NetworkMonitor
// tried to validate the private DNS but failed.
if (isStrictMode) {
@@ -782,7 +779,7 @@
mNmValidationRedirectUrl = redirectUrl;
// Suppose the portal is found when NetworkMonitor probes NETWORK_VALIDATION_PROBE_HTTP
// in the beginning, so the NETWORK_VALIDATION_PROBE_HTTPS hasn't probed yet.
- int probesCompleted = VALIDATION_RESULT_BASE & ~NETWORK_VALIDATION_PROBE_HTTPS;
+ int probesCompleted = NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTP;
int probesSucceeded = VALIDATION_RESULT_INVALID;
if (isStrictMode) {
probesCompleted |= NETWORK_VALIDATION_PROBE_PRIVDNS;
@@ -791,18 +788,20 @@
}
void setNetworkPartial() {
- mNmValidationResult = VALIDATION_RESULT_PARTIAL;
+ mNmValidationResult = NETWORK_VALIDATION_RESULT_PARTIAL;
mNmValidationRedirectUrl = null;
- int probesCompleted = VALIDATION_RESULT_BASE;
- int probesSucceeded = VALIDATION_RESULT_BASE & ~NETWORK_VALIDATION_PROBE_HTTPS;
+ int probesCompleted = NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTPS
+ | NETWORK_VALIDATION_PROBE_FALLBACK;
+ int probesSucceeded = NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_FALLBACK;
setProbesStatus(probesCompleted, probesSucceeded);
}
void setNetworkPartialValid(boolean isStrictMode) {
setNetworkPartial();
- mNmValidationResult |= VALIDATION_RESULT_VALID;
- int probesCompleted = VALIDATION_RESULT_BASE;
- int probesSucceeded = VALIDATION_RESULT_BASE & ~NETWORK_VALIDATION_PROBE_HTTPS;
+ mNmValidationResult |= NETWORK_VALIDATION_RESULT_VALID;
+ int probesCompleted = NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTPS
+ | NETWORK_VALIDATION_PROBE_HTTP;
+ int probesSucceeded = NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTP;
// Suppose the partial network cannot pass the private DNS validation as well, so only
// add NETWORK_VALIDATION_PROBE_DNS in probesCompleted but not probesSucceeded.
if (isStrictMode) {
@@ -838,8 +837,10 @@
}
void notifyDataStallSuspected() throws Exception {
- mNmCallbacks.notifyDataStallSuspected(
- DATA_STALL_TIMESTAMP, DATA_STALL_DETECTION_METHOD, mDataStallExtras);
+ final DataStallReportParcelable p = new DataStallReportParcelable();
+ p.detectionMethod = DATA_STALL_DETECTION_METHOD;
+ p.timestampMillis = DATA_STALL_TIMESTAMP;
+ mNmCallbacks.notifyDataStallSuspected(p);
}
}
diff --git a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
index 23098ec..529d03c 100644
--- a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
@@ -547,6 +547,16 @@
@Test
public void testApplyTransportModeTransform() throws Exception {
+ verifyApplyTransportModeTransformCommon(false);
+ }
+
+ @Test
+ public void testApplyTransportModeTransformReleasedSpi() throws Exception {
+ verifyApplyTransportModeTransformCommon(true);
+ }
+
+ public void verifyApplyTransportModeTransformCommon(
+ boolean closeSpiBeforeApply) throws Exception {
IpSecConfig ipSecConfig = new IpSecConfig();
addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
addAuthAndCryptToIpSecConfig(ipSecConfig);
@@ -554,6 +564,39 @@
IpSecTransformResponse createTransformResp =
mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
+ if (closeSpiBeforeApply) {
+ mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
+ }
+
+ Socket socket = new Socket();
+ socket.bind(null);
+ ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket);
+
+ int resourceId = createTransformResp.resourceId;
+ mIpSecService.applyTransportModeTransform(pfd, IpSecManager.DIRECTION_OUT, resourceId);
+
+ verify(mMockNetd)
+ .ipSecApplyTransportModeTransform(
+ eq(pfd),
+ eq(mUid),
+ eq(IpSecManager.DIRECTION_OUT),
+ anyString(),
+ anyString(),
+ eq(TEST_SPI));
+ }
+
+ @Test
+ public void testApplyTransportModeTransformWithClosedSpi() throws Exception {
+ IpSecConfig ipSecConfig = new IpSecConfig();
+ addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
+ addAuthAndCryptToIpSecConfig(ipSecConfig);
+
+ IpSecTransformResponse createTransformResp =
+ mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
+
+ // Close SPI record
+ mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
+
Socket socket = new Socket();
socket.bind(null);
ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket);
@@ -660,6 +703,15 @@
@Test
public void testApplyTunnelModeTransform() throws Exception {
+ verifyApplyTunnelModeTransformCommon(false);
+ }
+
+ @Test
+ public void testApplyTunnelModeTransformReleasedSpi() throws Exception {
+ verifyApplyTunnelModeTransformCommon(true);
+ }
+
+ public void verifyApplyTunnelModeTransformCommon(boolean closeSpiBeforeApply) throws Exception {
IpSecConfig ipSecConfig = new IpSecConfig();
ipSecConfig.setMode(IpSecTransform.MODE_TUNNEL);
addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
@@ -670,6 +722,49 @@
IpSecTunnelInterfaceResponse createTunnelResp =
createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage");
+ if (closeSpiBeforeApply) {
+ mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
+ }
+
+ int transformResourceId = createTransformResp.resourceId;
+ int tunnelResourceId = createTunnelResp.resourceId;
+ mIpSecService.applyTunnelModeTransform(tunnelResourceId, IpSecManager.DIRECTION_OUT,
+ transformResourceId, "blessedPackage");
+
+ for (int selAddrFamily : ADDRESS_FAMILIES) {
+ verify(mMockNetd)
+ .ipSecUpdateSecurityPolicy(
+ eq(mUid),
+ eq(selAddrFamily),
+ eq(IpSecManager.DIRECTION_OUT),
+ anyString(),
+ anyString(),
+ eq(TEST_SPI),
+ anyInt(), // iKey/oKey
+ anyInt(), // mask
+ eq(tunnelResourceId));
+ }
+
+ ipSecConfig.setXfrmInterfaceId(tunnelResourceId);
+ verifyTransformNetdCalledForCreatingSA(ipSecConfig, createTransformResp);
+ }
+
+
+ @Test
+ public void testApplyTunnelModeTransformWithClosedSpi() throws Exception {
+ IpSecConfig ipSecConfig = new IpSecConfig();
+ ipSecConfig.setMode(IpSecTransform.MODE_TUNNEL);
+ addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
+ addAuthAndCryptToIpSecConfig(ipSecConfig);
+
+ IpSecTransformResponse createTransformResp =
+ mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
+ IpSecTunnelInterfaceResponse createTunnelResp =
+ createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage");
+
+ // Close SPI record
+ mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
+
int transformResourceId = createTransformResp.resourceId;
int tunnelResourceId = createTunnelResp.resourceId;
mIpSecService.applyTunnelModeTransform(tunnelResourceId, IpSecManager.DIRECTION_OUT,
diff --git a/tests/net/java/com/android/server/net/NetworkStatsBaseTest.java b/tests/net/java/com/android/server/net/NetworkStatsBaseTest.java
index 28785f7..3aafe0b 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsBaseTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsBaseTest.java
@@ -41,6 +41,7 @@
static final String TEST_IFACE = "test0";
static final String TEST_IFACE2 = "test1";
static final String TUN_IFACE = "test_nss_tun0";
+ static final String TUN_IFACE2 = "test_nss_tun1";
static final int UID_RED = 1001;
static final int UID_BLUE = 1002;
@@ -107,10 +108,14 @@
assertEquals("unexpected operations", operations, entry.operations);
}
- VpnInfo createVpnInfo(String[] underlyingIfaces) {
+ static VpnInfo createVpnInfo(String[] underlyingIfaces) {
+ return createVpnInfo(TUN_IFACE, underlyingIfaces);
+ }
+
+ static VpnInfo createVpnInfo(String vpnIface, String[] underlyingIfaces) {
VpnInfo info = new VpnInfo();
info.ownerUid = UID_VPN;
- info.vpnIface = TUN_IFACE;
+ info.vpnIface = vpnIface;
info.underlyingIfaces = underlyingIfaces;
return info;
}
diff --git a/tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java b/tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java
index a21f509..4473492 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java
@@ -104,7 +104,7 @@
}
@Test
- public void vpnRewriteTrafficThroughItself() throws Exception {
+ public void testVpnRewriteTrafficThroughItself() throws Exception {
VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
mFactory.updateVpnInfos(vpnInfos);
@@ -133,7 +133,7 @@
}
@Test
- public void vpnWithClat() throws Exception {
+ public void testVpnWithClat() throws Exception {
VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {CLAT_PREFIX + TEST_IFACE})};
mFactory.updateVpnInfos(vpnInfos);
mFactory.noteStackedIface(CLAT_PREFIX + TEST_IFACE, TEST_IFACE);
@@ -166,7 +166,7 @@
}
@Test
- public void vpnWithOneUnderlyingIface() throws Exception {
+ public void testVpnWithOneUnderlyingIface() throws Exception {
VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
mFactory.updateVpnInfos(vpnInfos);
@@ -189,7 +189,7 @@
}
@Test
- public void vpnWithOneUnderlyingIfaceAndOwnTraffic() throws Exception {
+ public void testVpnWithOneUnderlyingIfaceAndOwnTraffic() throws Exception {
// WiFi network is connected and VPN is using WiFi (which has TEST_IFACE).
VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
mFactory.updateVpnInfos(vpnInfos);
@@ -217,7 +217,7 @@
}
@Test
- public void vpnWithOneUnderlyingIface_withCompression() throws Exception {
+ public void testVpnWithOneUnderlyingIface_withCompression() throws Exception {
// WiFi network is connected and VPN is using WiFi (which has TEST_IFACE).
VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
mFactory.updateVpnInfos(vpnInfos);
@@ -238,7 +238,7 @@
}
@Test
- public void vpnWithTwoUnderlyingIfaces_packetDuplication() throws Exception {
+ public void testVpnWithTwoUnderlyingIfaces_packetDuplication() throws Exception {
// WiFi and Cell networks are connected and VPN is using WiFi (which has TEST_IFACE) and
// Cell (which has TEST_IFACE2) and has declared both of them in its underlying network set.
// Additionally, VPN is duplicating traffic across both WiFi and Cell.
@@ -264,7 +264,47 @@
}
@Test
- public void vpnWithTwoUnderlyingIfaces_splitTraffic() throws Exception {
+ public void testConcurrentVpns() throws Exception {
+ // Assume two VPNs are connected on two different network interfaces. VPN1 is using
+ // TEST_IFACE and VPN2 is using TEST_IFACE2.
+ final VpnInfo[] vpnInfos = new VpnInfo[] {
+ createVpnInfo(TUN_IFACE, new String[] {TEST_IFACE}),
+ createVpnInfo(TUN_IFACE2, new String[] {TEST_IFACE2})};
+ mFactory.updateVpnInfos(vpnInfos);
+
+ // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
+ // overhead per packet):
+ // 1000 bytes (100 packets) were sent, and 2000 bytes (200 packets) were received by UID_RED
+ // over VPN1.
+ // 700 bytes (70 packets) were sent, and 3000 bytes (300 packets) were received by UID_RED
+ // over VPN2.
+ // 500 bytes (50 packets) were sent, and 1000 bytes (100 packets) were received by UID_BLUE
+ // over VPN1.
+ // 250 bytes (25 packets) were sent, and 500 bytes (50 packets) were received by UID_BLUE
+ // over VPN2.
+ // VPN1 sent 1650 bytes (150 packets), and received 3300 (300 packets) over TEST_IFACE.
+ // Of 1650 bytes sent over WiFi, expect 1000 bytes attributed to UID_RED, 500 bytes
+ // attributed to UID_BLUE, and 150 bytes attributed to UID_VPN.
+ // Of 3300 bytes received over WiFi, expect 2000 bytes attributed to UID_RED, 1000 bytes
+ // attributed to UID_BLUE, and 300 bytes attributed to UID_VPN.
+ // VPN2 sent 1045 bytes (95 packets), and received 3850 (350 packets) over TEST_IFACE2.
+ // Of 1045 bytes sent over Cell, expect 700 bytes attributed to UID_RED, 250 bytes
+ // attributed to UID_BLUE, and 95 bytes attributed to UID_VPN.
+ // Of 3850 bytes received over Cell, expect 3000 bytes attributed to UID_RED, 500 bytes
+ // attributed to UID_BLUE, and 350 bytes attributed to UID_VPN.
+ final NetworkStats tunStats =
+ parseDetailedStats(R.raw.xt_qtaguid_vpn_one_underlying_two_vpn);
+
+ assertValues(tunStats, TEST_IFACE, UID_RED, 2000L, 200L, 1000L, 100L);
+ assertValues(tunStats, TEST_IFACE, UID_BLUE, 1000L, 100L, 500L, 50L);
+ assertValues(tunStats, TEST_IFACE2, UID_RED, 3000L, 300L, 700L, 70L);
+ assertValues(tunStats, TEST_IFACE2, UID_BLUE, 500L, 50L, 250L, 25L);
+ assertValues(tunStats, TEST_IFACE, UID_VPN, 300L, 0L, 150L, 0L);
+ assertValues(tunStats, TEST_IFACE2, UID_VPN, 350L, 0L, 95L, 0L);
+ }
+
+ @Test
+ public void testVpnWithTwoUnderlyingIfaces_splitTraffic() throws Exception {
// WiFi and Cell networks are connected and VPN is using WiFi (which has TEST_IFACE) and
// Cell (which has TEST_IFACE2) and has declared both of them in its underlying network set.
// Additionally, VPN is arbitrarily splitting traffic across WiFi and Cell.
@@ -291,7 +331,7 @@
}
@Test
- public void vpnWithTwoUnderlyingIfaces_splitTrafficWithCompression() throws Exception {
+ public void testVpnWithTwoUnderlyingIfaces_splitTrafficWithCompression() throws Exception {
// WiFi and Cell networks are connected and VPN is using WiFi (which has TEST_IFACE) and
// Cell (which has TEST_IFACE2) and has declared both of them in its underlying network set.
// Additionally, VPN is arbitrarily splitting compressed traffic across WiFi and Cell.
@@ -314,7 +354,7 @@
}
@Test
- public void vpnWithIncorrectUnderlyingIface() throws Exception {
+ public void testVpnWithIncorrectUnderlyingIface() throws Exception {
// WiFi and Cell networks are connected and VPN is using Cell (which has TEST_IFACE2),
// but has declared only WiFi (TEST_IFACE) in its underlying network set.
VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
index 1db90b7..a1bb0d5 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -60,14 +60,13 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.app.AlarmManager;
import android.app.usage.NetworkStatsManager;
import android.content.Context;
@@ -95,8 +94,6 @@
import android.os.Messenger;
import android.os.PowerManager;
import android.os.SimpleClock;
-import android.telephony.PhoneStateListener;
-import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
import androidx.test.InstrumentationRegistry;
@@ -126,6 +123,7 @@
import java.time.Clock;
import java.time.ZoneOffset;
import java.util.Objects;
+import java.util.concurrent.Executor;
/**
* Tests for {@link NetworkStatsService}.
@@ -168,14 +166,13 @@
private @Mock NetworkStatsSettings mSettings;
private @Mock IBinder mBinder;
private @Mock AlarmManager mAlarmManager;
- private @Mock TelephonyManager mTelephonyManager;
+ @Mock
+ private NetworkStatsSubscriptionsMonitor mNetworkStatsSubscriptionsMonitor;
private HandlerThread mHandlerThread;
private NetworkStatsService mService;
private INetworkStatsSession mSession;
private INetworkManagementEventObserver mNetworkObserver;
- @Nullable
- private PhoneStateListener mPhoneStateListener;
private final Clock mClock = new SimpleClock(ZoneOffset.UTC) {
@Override
@@ -203,8 +200,8 @@
mHandlerThread = new HandlerThread("HandlerThread");
final NetworkStatsService.Dependencies deps = makeDependencies();
mService = new NetworkStatsService(mServiceContext, mNetManager, mAlarmManager, wakeLock,
- mClock, mTelephonyManager, mSettings,
- mStatsFactory, new NetworkStatsObservers(), mStatsDir, getBaseDir(mStatsDir), deps);
+ mClock, mSettings, mStatsFactory, new NetworkStatsObservers(), mStatsDir,
+ getBaseDir(mStatsDir), deps);
mElapsedRealtime = 0L;
@@ -224,12 +221,6 @@
ArgumentCaptor.forClass(INetworkManagementEventObserver.class);
verify(mNetManager).registerObserver(networkObserver.capture());
mNetworkObserver = networkObserver.getValue();
-
- // Capture the phone state listener that created by service.
- final ArgumentCaptor<PhoneStateListener> phoneStateListenerCaptor =
- ArgumentCaptor.forClass(PhoneStateListener.class);
- verify(mTelephonyManager).listen(phoneStateListenerCaptor.capture(), anyInt());
- mPhoneStateListener = phoneStateListenerCaptor.getValue();
}
@NonNull
@@ -239,6 +230,14 @@
public HandlerThread makeHandlerThread() {
return mHandlerThread;
}
+
+ @Override
+ public NetworkStatsSubscriptionsMonitor makeSubscriptionsMonitor(
+ @NonNull Context context, @NonNull Executor executor,
+ @NonNull NetworkStatsService service) {
+
+ return mNetworkStatsSubscriptionsMonitor;
+ }
};
}
@@ -678,10 +677,9 @@
// TODO: support per IMSI state
private void setMobileRatTypeAndWaitForIdle(int ratType) {
- final ServiceState mockSs = mock(ServiceState.class);
- when(mockSs.getDataNetworkType()).thenReturn(ratType);
- mPhoneStateListener.onServiceStateChanged(mockSs);
-
+ when(mNetworkStatsSubscriptionsMonitor.getRatTypeForSubscriberId(anyString()))
+ .thenReturn(ratType);
+ mService.handleOnCollapsedRatTypeChanged();
HandlerUtilsKt.waitForIdle(mHandlerThread, WAIT_TIMEOUT);
}
diff --git a/tests/net/res/raw/xt_qtaguid_vpn_one_underlying_two_vpn b/tests/net/res/raw/xt_qtaguid_vpn_one_underlying_two_vpn
new file mode 100644
index 0000000..eb0513b
--- /dev/null
+++ b/tests/net/res/raw/xt_qtaguid_vpn_one_underlying_two_vpn
@@ -0,0 +1,9 @@
+idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packets rx_tcp_bytes rx_tcp_packets rx_udp_bytes rx_udp_packets rx_other_bytes rx_other_packets tx_tcp_bytes tx_tcp_packets tx_udp_bytes tx_udp_packets tx_other_bytes tx_other_packets
+2 test_nss_tun0 0x0 1001 0 2000 200 1000 100 0 0 0 0 0 0 0 0 0 0 0 0
+3 test_nss_tun0 0x0 1002 0 1000 100 500 50 0 0 0 0 0 0 0 0 0 0 0 0
+4 test_nss_tun1 0x0 1001 0 3000 300 700 70 0 0 0 0 0 0 0 0 0 0 0 0
+5 test_nss_tun1 0x0 1002 0 500 50 250 25 0 0 0 0 0 0 0 0 0 0 0 0
+6 test0 0x0 1004 0 3300 300 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+7 test0 0x0 1004 1 0 0 1650 150 0 0 0 0 0 0 0 0 0 0 0 0
+8 test1 0x0 1004 0 3850 350 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+9 test1 0x0 1004 1 0 0 1045 95 0 0 0 0 0 0 0 0 0 0 0 0
\ No newline at end of file