From c78da2937cf79e11d439df7730fa29c82b177ab3 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 19 Jan 2018 00:50:48 +0900 Subject: [PATCH] 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 --- core/java/android/net/INetworkStatsService.aidl | 3 +- .../com/android/server/ConnectivityService.java | 24 +++++++++++-- .../android/server/net/NetworkStatsService.java | 27 ++++++++++---- .../android/server/ConnectivityServiceTest.java | 26 +++++++++++--- .../server/net/NetworkStatsServiceTest.java | 41 +++++++++++++--------- 5 files changed, 90 insertions(+), 31 deletions(-) diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index 95e7f6031c72..90e3ffd550b4 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -18,6 +18,7 @@ package android.net; 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 @@ interface INetworkStatsService { 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 56d7e7b9304a..08a7a485cc8b 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -4962,10 +4962,12 @@ public class ConnectivityService extends IConnectivityManager.Stub } 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 @@ public class ConnectivityService extends IConnectivityManager.Stub } /** + * 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 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 @@ public class ConnectivityService extends IConnectivityManager.Stub 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 db61ef5cd9b9..0b25573c30ef 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.INetworkManagementEventObserver; 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 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private final Object mStatsLock = new Object(); /** Set of currently active ifaces. */ + @GuardedBy("mStatsLock") private final ArrayMap mActiveIfaces = new ArrayMap<>(); + /** Set of currently active ifaces for UID stats. */ + @GuardedBy("mStatsLock") private final ArrayMap 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 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @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 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } }; - private void updateIfaces() { + private void updateIfaces(Network[] defaultNetworks) { synchronized (mStatsLock) { mWakeLock.acquire(); try { - updateIfacesLocked(); + updateIfacesLocked(defaultNetworks); } finally { mWakeLock.release(); } @@ -1013,7 +1024,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * 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 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // 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 mobileIfaces = new ArraySet<>(); for (NetworkState state : states) { @@ -1511,7 +1526,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { 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 b8e37f3a10ea..70cacb3af009 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -3501,34 +3501,50 @@ public class ConnectivityServiceTest { @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 ecc99323d7d7..1f2309d18c05 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.IConnectivityManager; 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 @@ public class NetworkStatsServiceTest { 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 @@ public class NetworkStatsServiceTest { 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 @@ public class NetworkStatsServiceTest { 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 @@ public class NetworkStatsServiceTest { expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(); + mService.forceUpdateIfaces(NETWORKS_WIFI); // modify some number on wifi, and trigger poll event @@ -401,7 +408,7 @@ public class NetworkStatsServiceTest { expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(); + mService.forceUpdateIfaces(NETWORKS_MOBILE); // create some traffic on first network @@ -439,7 +446,7 @@ public class NetworkStatsServiceTest { .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 @@ public class NetworkStatsServiceTest { expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(); + mService.forceUpdateIfaces(NETWORKS_WIFI); // create some traffic @@ -543,7 +550,7 @@ public class NetworkStatsServiceTest { expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(); + mService.forceUpdateIfaces(NETWORKS_MOBILE); // create some traffic @@ -573,7 +580,7 @@ public class NetworkStatsServiceTest { .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 @@ public class NetworkStatsServiceTest { expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(); + mService.forceUpdateIfaces(NETWORKS_WIFI); // create some traffic for two apps @@ -667,7 +674,7 @@ public class NetworkStatsServiceTest { expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(); + mService.forceUpdateIfaces(NETWORKS_WIFI); // create some initial traffic @@ -728,7 +735,7 @@ public class NetworkStatsServiceTest { expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(); + mService.forceUpdateIfaces(NETWORKS_WIFI); // create some initial traffic @@ -770,7 +777,7 @@ public class NetworkStatsServiceTest { expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(); + mService.forceUpdateIfaces(NETWORKS_MOBILE); // Create some traffic @@ -811,7 +818,7 @@ public class NetworkStatsServiceTest { expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(); + mService.forceUpdateIfaces(NETWORKS_MOBILE); // create some tethering traffic @@ -856,7 +863,7 @@ public class NetworkStatsServiceTest { 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 @@ public class NetworkStatsServiceTest { 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 @@ public class NetworkStatsServiceTest { 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 @@ public class NetworkStatsServiceTest { 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() { -- 2.11.0