Pass all default networks to NetworkStatsService
This will allow NetworkStatsService to treat traffic on these
networks differently from traffic where the app selects a network
that is not the default.
Bug: 35142602
Test: runtest frameworks-net
Change-Id: I5ea9d200d9fb153490c6108bb9390bf152f297da
diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl
index 95e7f60..90e3ffd 100644
--- a/core/java/android/net/INetworkStatsService.aidl
+++ b/core/java/android/net/INetworkStatsService.aidl
@@ -18,6 +18,7 @@
import android.net.DataUsageRequest;
import android.net.INetworkStatsSession;
+import android.net.Network;
import android.net.NetworkStats;
import android.net.NetworkStatsHistory;
import android.net.NetworkTemplate;
@@ -53,7 +54,7 @@
void setUidForeground(int uid, boolean uidForeground);
/** Force update of ifaces. */
- void forceUpdateIfaces();
+ void forceUpdateIfaces(in Network[] defaultNetworks);
/** Force update of statistics. */
void forceUpdate();
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 56d7e7b..08a7a48 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -4962,10 +4962,12 @@
} catch (Exception e) {
loge("Exception setting default network :" + e);
}
+
notifyLockdownVpn(newNetwork);
handleApplyDefaultProxy(newNetwork.linkProperties.getHttpProxy());
updateTcpBufferSizes(newNetwork);
mDnsManager.setDefaultDnsSystemProperties(newNetwork.linkProperties.getDnsServers());
+ notifyIfacesChangedForNetworkStats();
}
private void processListenRequests(NetworkAgentInfo nai, boolean capabilitiesChanged) {
@@ -5539,12 +5541,30 @@
}
/**
+ * Returns the list of all interfaces that could be used by network traffic that does not
+ * explicitly specify a network. This includes the default network, but also all VPNs that are
+ * currently connected.
+ *
+ * Must be called on the handler thread.
+ */
+ private Network[] getDefaultNetworks() {
+ ArrayList<Network> defaultNetworks = new ArrayList<>();
+ NetworkAgentInfo defaultNetwork = getDefaultNetwork();
+ for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
+ if (nai.everConnected && (nai == defaultNetwork || nai.isVPN())) {
+ defaultNetworks.add(nai.network);
+ }
+ }
+ return defaultNetworks.toArray(new Network[0]);
+ }
+
+ /**
* Notify NetworkStatsService that the set of active ifaces has changed, or that one of the
* properties tracked by NetworkStatsService on an active iface has changed.
*/
private void notifyIfacesChangedForNetworkStats() {
try {
- mStatsService.forceUpdateIfaces();
+ mStatsService.forceUpdateIfaces(getDefaultNetworks());
} catch (Exception ignored) {
}
}
@@ -5576,7 +5596,7 @@
success = mVpns.get(user).setUnderlyingNetworks(networks);
}
if (success) {
- notifyIfacesChangedForNetworkStats();
+ mHandler.post(() -> notifyIfacesChangedForNetworkStats());
}
return success;
}
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index db61ef5..0b25573 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -83,6 +83,7 @@
import android.net.INetworkStatsService;
import android.net.INetworkStatsSession;
import android.net.LinkProperties;
+import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkIdentity;
import android.net.NetworkInfo;
@@ -231,14 +232,24 @@
private final Object mStatsLock = new Object();
/** Set of currently active ifaces. */
+ @GuardedBy("mStatsLock")
private final ArrayMap<String, NetworkIdentitySet> mActiveIfaces = new ArrayMap<>();
+
/** Set of currently active ifaces for UID stats. */
+ @GuardedBy("mStatsLock")
private final ArrayMap<String, NetworkIdentitySet> mActiveUidIfaces = new ArrayMap<>();
+
/** Current default active iface. */
private String mActiveIface;
+
/** Set of any ifaces associated with mobile networks since boot. */
+ @GuardedBy("mStatsLock")
private String[] mMobileIfaces = new String[0];
+ /** Set of all ifaces currently used by traffic that does not explicitly specify a Network. */
+ @GuardedBy("mStatsLock")
+ private Network[] mDefaultNetworks = new Network[0];
+
private final DropBoxNonMonotonicObserver mNonMonotonicObserver =
new DropBoxNonMonotonicObserver();
@@ -779,13 +790,13 @@
}
@Override
- public void forceUpdateIfaces() {
+ public void forceUpdateIfaces(Network[] defaultNetworks) {
mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
assertBandwidthControlEnabled();
final long token = Binder.clearCallingIdentity();
try {
- updateIfaces();
+ updateIfaces(defaultNetworks);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -996,11 +1007,11 @@
}
};
- private void updateIfaces() {
+ private void updateIfaces(Network[] defaultNetworks) {
synchronized (mStatsLock) {
mWakeLock.acquire();
try {
- updateIfacesLocked();
+ updateIfacesLocked(defaultNetworks);
} finally {
mWakeLock.release();
}
@@ -1013,7 +1024,7 @@
* are active on a single {@code iface}, they are combined under a single
* {@link NetworkIdentitySet}.
*/
- private void updateIfacesLocked() {
+ private void updateIfacesLocked(Network[] defaultNetworks) {
if (!mSystemReady) return;
if (LOGV) Slog.v(TAG, "updateIfacesLocked()");
@@ -1040,6 +1051,10 @@
// Rebuild active interfaces based on connected networks
mActiveIfaces.clear();
mActiveUidIfaces.clear();
+ if (defaultNetworks != null) {
+ // Caller is ConnectivityService. Update the list of default networks.
+ mDefaultNetworks = defaultNetworks;
+ }
final ArraySet<String> mobileIfaces = new ArraySet<>();
for (NetworkState state : states) {
@@ -1511,7 +1526,7 @@
return true;
}
case MSG_UPDATE_IFACES: {
- mService.updateIfaces();
+ mService.updateIfaces(null);
return true;
}
case MSG_REGISTER_GLOBAL_ALERT: {
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index b8e37f3..70cacb3 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -3501,34 +3501,50 @@
@Test
public void testStatsIfacesChanged() throws Exception {
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+
+ Network[] onlyCell = new Network[]{mCellNetworkAgent.getNetwork()};
+ Network[] onlyWifi = new Network[]{mWiFiNetworkAgent.getNetwork()};
// Simple connection should have updated ifaces
mCellNetworkAgent.connect(false);
waitForIdle();
- verify(mStatsService, atLeastOnce()).forceUpdateIfaces();
+ verify(mStatsService, atLeastOnce()).forceUpdateIfaces(onlyCell);
+ reset(mStatsService);
+
+ // Default network switch should update ifaces.
+ mWiFiNetworkAgent.connect(false);
+ waitForIdle();
+ verify(mStatsService, atLeastOnce()).forceUpdateIfaces(onlyWifi);
+ reset(mStatsService);
+
+ // Disconnect should update ifaces.
+ mWiFiNetworkAgent.disconnect();
+ waitForIdle();
+ verify(mStatsService, atLeastOnce()).forceUpdateIfaces(onlyCell);
reset(mStatsService);
// Metered change should update ifaces
mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
waitForIdle();
- verify(mStatsService, atLeastOnce()).forceUpdateIfaces();
+ verify(mStatsService, atLeastOnce()).forceUpdateIfaces(onlyCell);
reset(mStatsService);
mCellNetworkAgent.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
waitForIdle();
- verify(mStatsService, atLeastOnce()).forceUpdateIfaces();
+ verify(mStatsService, atLeastOnce()).forceUpdateIfaces(onlyCell);
reset(mStatsService);
// Captive portal change shouldn't update ifaces
mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL);
waitForIdle();
- verify(mStatsService, never()).forceUpdateIfaces();
+ verify(mStatsService, never()).forceUpdateIfaces(onlyCell);
reset(mStatsService);
// Roaming change should update ifaces
mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING);
waitForIdle();
- verify(mStatsService, atLeastOnce()).forceUpdateIfaces();
+ verify(mStatsService, atLeastOnce()).forceUpdateIfaces(onlyCell);
reset(mStatsService);
}
diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
index ecc9932..1f2309d 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -67,6 +67,7 @@
import android.net.INetworkManagementEventObserver;
import android.net.INetworkStatsSession;
import android.net.LinkProperties;
+import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
@@ -136,6 +137,12 @@
private static final int UID_BLUE = 1002;
private static final int UID_GREEN = 1003;
+
+ private static final Network WIFI_NETWORK = new Network(100);
+ private static final Network MOBILE_NETWORK = new Network(101);
+ private static final Network[] NETWORKS_WIFI = new Network[]{ WIFI_NETWORK };
+ private static final Network[] NETWORKS_MOBILE = new Network[]{ MOBILE_NETWORK };
+
private static final long WAIT_TIMEOUT = 2 * 1000; // 2 secs
private static final int INVALID_TYPE = -1;
@@ -231,7 +238,7 @@
expectNetworkStatsUidDetail(buildEmptyStats());
expectBandwidthControlCheck();
- mService.forceUpdateIfaces();
+ mService.forceUpdateIfaces(NETWORKS_WIFI);
// verify service has empty history for wifi
assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
@@ -278,7 +285,7 @@
expectNetworkStatsUidDetail(buildEmptyStats());
expectBandwidthControlCheck();
- mService.forceUpdateIfaces();
+ mService.forceUpdateIfaces(NETWORKS_WIFI);
// verify service has empty history for wifi
assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
@@ -356,7 +363,7 @@
expectNetworkStatsUidDetail(buildEmptyStats());
expectBandwidthControlCheck();
- mService.forceUpdateIfaces();
+ mService.forceUpdateIfaces(NETWORKS_WIFI);
// modify some number on wifi, and trigger poll event
@@ -401,7 +408,7 @@
expectNetworkStatsUidDetail(buildEmptyStats());
expectBandwidthControlCheck();
- mService.forceUpdateIfaces();
+ mService.forceUpdateIfaces(NETWORKS_MOBILE);
// create some traffic on first network
@@ -439,7 +446,7 @@
.addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 512L, 4L, 0L, 0L, 0L));
expectBandwidthControlCheck();
- mService.forceUpdateIfaces();
+ mService.forceUpdateIfaces(NETWORKS_MOBILE);
forcePollAndWaitForIdle();
@@ -481,7 +488,7 @@
expectNetworkStatsUidDetail(buildEmptyStats());
expectBandwidthControlCheck();
- mService.forceUpdateIfaces();
+ mService.forceUpdateIfaces(NETWORKS_WIFI);
// create some traffic
@@ -543,7 +550,7 @@
expectNetworkStatsUidDetail(buildEmptyStats());
expectBandwidthControlCheck();
- mService.forceUpdateIfaces();
+ mService.forceUpdateIfaces(NETWORKS_MOBILE);
// create some traffic
@@ -573,7 +580,7 @@
.addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L));
expectBandwidthControlCheck();
- mService.forceUpdateIfaces();
+ mService.forceUpdateIfaces(NETWORKS_MOBILE);
forcePollAndWaitForIdle();
@@ -605,7 +612,7 @@
expectNetworkStatsUidDetail(buildEmptyStats());
expectBandwidthControlCheck();
- mService.forceUpdateIfaces();
+ mService.forceUpdateIfaces(NETWORKS_WIFI);
// create some traffic for two apps
@@ -667,7 +674,7 @@
expectNetworkStatsUidDetail(buildEmptyStats());
expectBandwidthControlCheck();
- mService.forceUpdateIfaces();
+ mService.forceUpdateIfaces(NETWORKS_WIFI);
// create some initial traffic
@@ -728,7 +735,7 @@
expectNetworkStatsUidDetail(buildEmptyStats());
expectBandwidthControlCheck();
- mService.forceUpdateIfaces();
+ mService.forceUpdateIfaces(NETWORKS_WIFI);
// create some initial traffic
@@ -770,7 +777,7 @@
expectNetworkStatsUidDetail(buildEmptyStats());
expectBandwidthControlCheck();
- mService.forceUpdateIfaces();
+ mService.forceUpdateIfaces(NETWORKS_MOBILE);
// Create some traffic
@@ -811,7 +818,7 @@
expectNetworkStatsUidDetail(buildEmptyStats());
expectBandwidthControlCheck();
- mService.forceUpdateIfaces();
+ mService.forceUpdateIfaces(NETWORKS_MOBILE);
// create some tethering traffic
@@ -856,7 +863,7 @@
expectNetworkStatsUidDetail(buildEmptyStats());
expectBandwidthControlCheck();
- mService.forceUpdateIfaces();
+ mService.forceUpdateIfaces(NETWORKS_WIFI);
// verify service has empty history for wifi
assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
@@ -1161,7 +1168,7 @@
final NetworkCapabilities capabilities = new NetworkCapabilities();
capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, !isMetered);
capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, true);
- return new NetworkState(info, prop, capabilities, null, null, TEST_SSID);
+ return new NetworkState(info, prop, capabilities, WIFI_NETWORK, null, TEST_SSID);
}
private static NetworkState buildMobile3gState(String subscriberId) {
@@ -1178,7 +1185,7 @@
final NetworkCapabilities capabilities = new NetworkCapabilities();
capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, false);
capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, !isRoaming);
- return new NetworkState(info, prop, capabilities, null, subscriberId, null);
+ return new NetworkState(info, prop, capabilities, MOBILE_NETWORK, subscriberId, null);
}
private static NetworkState buildMobile4gState(String iface) {
@@ -1189,7 +1196,7 @@
final NetworkCapabilities capabilities = new NetworkCapabilities();
capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, false);
capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, true);
- return new NetworkState(info, prop, capabilities, null, null, null);
+ return new NetworkState(info, prop, capabilities, MOBILE_NETWORK, null, null);
}
private NetworkStats buildEmptyStats() {