From 5455c0ee6fa9adf40648ad33d59df64cd984a5c5 Mon Sep 17 00:00:00 2001 From: Varun Anand Date: Thu, 7 Feb 2019 14:13:13 -0800 Subject: [PATCH 1/3] Remove ConnectivityManager and its usages from NetworkStatsService. NSS needed it for getting VpnInfo[], NetworkState[] and activeLinkProperties which it used to query via ConnectivityManager. For VpnInfo[], this was racy as NSS may ignore intermediate changes to a VPN's underlying networks. See http://b/123961098 for more context. It may also lead to deadlocks b/w ConnectivityService and NetworkStatsService. See http://b/126245192 for more info. This change will ensure that NSS is never contending on any of ConnectivityService locks. This change also is cherry-picking cleanup made to NSS in http://aosp/628368. Bug: 123961098 Bug: 126245192 Bug: 120145746 Test: atest FrameworksNetTests Change-Id: Ia687845888434c8ddd24bdf44b4c70dfe80e03f5 Merged-In: I57e117bb4e9efe491b19d6b5a479f2d58d1c58e6 --- .../android/net/IConnectivityManager.aidl | 2 - .../android/server/ConnectivityService.java | 22 +++-- .../server/ConnectivityServiceTest.java | 63 ++++++++++++--- .../server/net/NetworkStatsServiceTest.java | 81 +++++++++---------- 4 files changed, 108 insertions(+), 60 deletions(-) diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index ce95b60dd2..83c862f753 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -120,8 +120,6 @@ interface IConnectivityManager LegacyVpnInfo getLegacyVpnInfo(int userId); - VpnInfo[] getAllVpnInfo(); - boolean updateLockdownVpn(); boolean isAlwaysOnVpnPackageSupported(int userId, String packageName); boolean setAlwaysOnVpnPackage(int userId, String packageName, boolean lockdown); diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 1c66c5a771..17cece1a22 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -3743,12 +3743,14 @@ public class ConnectivityService extends IConnectivityManager.Stub } /** - * Return the information of all ongoing VPNs. This method is used by NetworkStatsService - * and not available in ConnectivityManager. + * Return the information of all ongoing VPNs. + * + *

This method is used to update NetworkStatsService. + * + *

Must be called on the handler thread. */ - @Override - public VpnInfo[] getAllVpnInfo() { - enforceConnectivityInternalPermission(); + private VpnInfo[] getAllVpnInfo() { + ensureRunningOnConnectivityServiceThread(); synchronized (mVpns) { if (mLockdownEnabled) { return new VpnInfo[0]; @@ -5816,6 +5818,7 @@ public class ConnectivityService extends IConnectivityManager.Stub * Must be called on the handler thread. */ private Network[] getDefaultNetworks() { + ensureRunningOnConnectivityServiceThread(); ArrayList defaultNetworks = new ArrayList<>(); NetworkAgentInfo defaultNetwork = getDefaultNetwork(); for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) { @@ -5831,8 +5834,15 @@ public class ConnectivityService extends IConnectivityManager.Stub * properties tracked by NetworkStatsService on an active iface has changed. */ private void notifyIfacesChangedForNetworkStats() { + ensureRunningOnConnectivityServiceThread(); + String activeIface = null; + LinkProperties activeLinkProperties = getActiveLinkProperties(); + if (activeLinkProperties != null) { + activeIface = activeLinkProperties.getInterfaceName(); + } try { - mStatsService.forceUpdateIfaces(getDefaultNetworks()); + mStatsService.forceUpdateIfaces( + getDefaultNetworks(), getAllVpnInfo(), getAllNetworkState(), activeIface); } catch (Exception ignored) { } } diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 0dcb21ab83..e6a889b1c2 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -109,6 +109,7 @@ import android.net.NetworkInfo.DetailedState; import android.net.NetworkMisc; import android.net.NetworkRequest; import android.net.NetworkSpecifier; +import android.net.NetworkState; import android.net.NetworkUtils; import android.net.RouteInfo; import android.net.StringNetworkSpecifier; @@ -137,6 +138,7 @@ import android.util.ArraySet; import android.util.Log; import com.android.internal.net.VpnConfig; +import com.android.internal.net.VpnInfo; import com.android.internal.util.ArrayUtils; import com.android.internal.util.WakeupMessage; import com.android.internal.util.test.BroadcastInterceptingContext; @@ -3813,48 +3815,91 @@ public class ConnectivityServiceTest { mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); - Network[] onlyCell = new Network[]{mCellNetworkAgent.getNetwork()}; - Network[] onlyWifi = new Network[]{mWiFiNetworkAgent.getNetwork()}; + Network[] onlyCell = new Network[] {mCellNetworkAgent.getNetwork()}; + Network[] onlyWifi = new Network[] {mWiFiNetworkAgent.getNetwork()}; + + LinkProperties cellLp = new LinkProperties(); + cellLp.setInterfaceName(MOBILE_IFNAME); + LinkProperties wifiLp = new LinkProperties(); + wifiLp.setInterfaceName(WIFI_IFNAME); // Simple connection should have updated ifaces mCellNetworkAgent.connect(false); + mCellNetworkAgent.sendLinkProperties(cellLp); waitForIdle(); - verify(mStatsService, atLeastOnce()).forceUpdateIfaces(onlyCell); + verify(mStatsService, atLeastOnce()) + .forceUpdateIfaces( + eq(onlyCell), + eq(new VpnInfo[0]), + any(NetworkState[].class), + eq(MOBILE_IFNAME)); reset(mStatsService); // Default network switch should update ifaces. mWiFiNetworkAgent.connect(false); + mWiFiNetworkAgent.sendLinkProperties(wifiLp); waitForIdle(); - verify(mStatsService, atLeastOnce()).forceUpdateIfaces(onlyWifi); + assertEquals(wifiLp, mService.getActiveLinkProperties()); + verify(mStatsService, atLeastOnce()) + .forceUpdateIfaces( + eq(onlyWifi), + eq(new VpnInfo[0]), + any(NetworkState[].class), + eq(WIFI_IFNAME)); reset(mStatsService); // Disconnect should update ifaces. mWiFiNetworkAgent.disconnect(); waitForIdle(); - verify(mStatsService, atLeastOnce()).forceUpdateIfaces(onlyCell); + verify(mStatsService, atLeastOnce()) + .forceUpdateIfaces( + eq(onlyCell), + eq(new VpnInfo[0]), + any(NetworkState[].class), + eq(MOBILE_IFNAME)); reset(mStatsService); // Metered change should update ifaces mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); waitForIdle(); - verify(mStatsService, atLeastOnce()).forceUpdateIfaces(onlyCell); + verify(mStatsService, atLeastOnce()) + .forceUpdateIfaces( + eq(onlyCell), + eq(new VpnInfo[0]), + any(NetworkState[].class), + eq(MOBILE_IFNAME)); reset(mStatsService); mCellNetworkAgent.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); waitForIdle(); - verify(mStatsService, atLeastOnce()).forceUpdateIfaces(onlyCell); + verify(mStatsService, atLeastOnce()) + .forceUpdateIfaces( + eq(onlyCell), + eq(new VpnInfo[0]), + any(NetworkState[].class), + eq(MOBILE_IFNAME)); reset(mStatsService); // Captive portal change shouldn't update ifaces mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL); waitForIdle(); - verify(mStatsService, never()).forceUpdateIfaces(onlyCell); + verify(mStatsService, never()) + .forceUpdateIfaces( + eq(onlyCell), + eq(new VpnInfo[0]), + any(NetworkState[].class), + eq(MOBILE_IFNAME)); reset(mStatsService); // Roaming change should update ifaces mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING); waitForIdle(); - verify(mStatsService, atLeastOnce()).forceUpdateIfaces(onlyCell); + verify(mStatsService, atLeastOnce()) + .forceUpdateIfaces( + eq(onlyCell), + eq(new VpnInfo[0]), + any(NetworkState[].class), + eq(MOBILE_IFNAME)); 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 e371abcb26..7cf1dc460b 100644 --- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java +++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java @@ -70,7 +70,6 @@ import android.app.usage.NetworkStatsManager; import android.content.Context; import android.content.Intent; import android.net.DataUsageRequest; -import android.net.IConnectivityManager; import android.net.INetworkManagementEventObserver; import android.net.INetworkStatsSession; import android.net.LinkProperties; @@ -163,7 +162,6 @@ public class NetworkStatsServiceTest { private @Mock INetworkManagementService mNetManager; private @Mock NetworkStatsSettings mSettings; - private @Mock IConnectivityManager mConnManager; private @Mock IBinder mBinder; private @Mock AlarmManager mAlarmManager; private HandlerThread mHandlerThread; @@ -205,7 +203,6 @@ public class NetworkStatsServiceTest { Handler.Callback callback = new NetworkStatsService.HandlerCallback(mService); mHandler = new Handler(mHandlerThread.getLooper(), callback); mService.setHandler(mHandler, callback); - mService.bindConnectivityManager(mConnManager); mElapsedRealtime = 0L; @@ -237,7 +234,6 @@ public class NetworkStatsServiceTest { mNetManager = null; mSettings = null; - mConnManager = null; mSession.close(); mService = null; @@ -248,12 +244,12 @@ public class NetworkStatsServiceTest { // pretend that wifi network comes online; service should ask about full // network state, and poll any existing interfaces before updating. expectDefaultSettings(); - expectNetworkState(buildWifiState()); + NetworkState[] states = new NetworkState[] {buildWifiState()}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_WIFI); + mService.forceUpdateIfaces(NETWORKS_WIFI, new VpnInfo[0], states, getActiveIface(states)); // verify service has empty history for wifi assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0); @@ -292,12 +288,12 @@ public class NetworkStatsServiceTest { // pretend that wifi network comes online; service should ask about full // network state, and poll any existing interfaces before updating. expectDefaultSettings(); - expectNetworkState(buildWifiState()); + NetworkState[] states = new NetworkState[] {buildWifiState()}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_WIFI); + mService.forceUpdateIfaces(NETWORKS_WIFI, new VpnInfo[0], states, getActiveIface(states)); // verify service has empty history for wifi assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0); @@ -366,12 +362,12 @@ public class NetworkStatsServiceTest { // pretend that wifi network comes online; service should ask about full // network state, and poll any existing interfaces before updating. expectSettings(0L, HOUR_IN_MILLIS, WEEK_IN_MILLIS); - expectNetworkState(buildWifiState()); + NetworkState[] states = new NetworkState[] {buildWifiState()}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_WIFI); + mService.forceUpdateIfaces(NETWORKS_WIFI, new VpnInfo[0], states, getActiveIface(states)); // modify some number on wifi, and trigger poll event @@ -408,12 +404,12 @@ public class NetworkStatsServiceTest { public void testUidStatsAcrossNetworks() throws Exception { // pretend first mobile network comes online expectDefaultSettings(); - expectNetworkState(buildMobile3gState(IMSI_1)); + NetworkState[] states = new NetworkState[] {buildMobile3gState(IMSI_1)}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_MOBILE); + mService.forceUpdateIfaces(NETWORKS_MOBILE, new VpnInfo[0], states, getActiveIface(states)); // create some traffic on first network @@ -440,7 +436,7 @@ public class NetworkStatsServiceTest { // disappearing, to verify we don't count backwards. incrementCurrentTime(HOUR_IN_MILLIS); expectDefaultSettings(); - expectNetworkState(buildMobile3gState(IMSI_2)); + states = new NetworkState[] {buildMobile3gState(IMSI_2)}; expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1) .addIfaceValues(TEST_IFACE, 2048L, 16L, 512L, 4L)); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3) @@ -449,7 +445,7 @@ public class NetworkStatsServiceTest { .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 512L, 4L, 0L, 0L, 0L)); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_MOBILE); + mService.forceUpdateIfaces(NETWORKS_MOBILE, new VpnInfo[0], states, getActiveIface(states)); forcePollAndWaitForIdle(); @@ -484,12 +480,12 @@ public class NetworkStatsServiceTest { public void testUidRemovedIsMoved() throws Exception { // pretend that network comes online expectDefaultSettings(); - expectNetworkState(buildWifiState()); + NetworkState[] states = new NetworkState[] {buildWifiState()}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_WIFI); + mService.forceUpdateIfaces(NETWORKS_WIFI, new VpnInfo[0], states, getActiveIface(states)); // create some traffic @@ -543,12 +539,12 @@ public class NetworkStatsServiceTest { public void testUid3g4gCombinedByTemplate() throws Exception { // pretend that network comes online expectDefaultSettings(); - expectNetworkState(buildMobile3gState(IMSI_1)); + NetworkState[] states = new NetworkState[] {buildMobile3gState(IMSI_1)}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_MOBILE); + mService.forceUpdateIfaces(NETWORKS_MOBILE, new VpnInfo[0], states, getActiveIface(states)); // create some traffic @@ -569,14 +565,14 @@ public class NetworkStatsServiceTest { // now switch over to 4g network incrementCurrentTime(HOUR_IN_MILLIS); expectDefaultSettings(); - expectNetworkState(buildMobile4gState(TEST_IFACE2)); + states = new NetworkState[] {buildMobile4gState(TEST_IFACE2)}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L) .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_MOBILE); + mService.forceUpdateIfaces(NETWORKS_MOBILE, new VpnInfo[0], states, getActiveIface(states)); forcePollAndWaitForIdle(); @@ -601,12 +597,12 @@ public class NetworkStatsServiceTest { public void testSummaryForAllUid() throws Exception { // pretend that network comes online expectDefaultSettings(); - expectNetworkState(buildWifiState()); + NetworkState[] states = new NetworkState[] {buildWifiState()}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_WIFI); + mService.forceUpdateIfaces(NETWORKS_WIFI, new VpnInfo[0], states, getActiveIface(states)); // create some traffic for two apps @@ -660,12 +656,12 @@ public class NetworkStatsServiceTest { public void testDetailedUidStats() throws Exception { // pretend that network comes online expectDefaultSettings(); - expectNetworkState(buildWifiState()); + NetworkState[] states = new NetworkState[] {buildWifiState()}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_WIFI); + mService.forceUpdateIfaces(NETWORKS_WIFI, new VpnInfo[0], states, getActiveIface(states)); NetworkStats.Entry entry1 = new NetworkStats.Entry( TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 50L, 5L, 50L, 5L, 0L); @@ -703,13 +699,13 @@ public class NetworkStatsServiceTest { stackedProp.setInterfaceName(stackedIface); final NetworkState wifiState = buildWifiState(); wifiState.linkProperties.addStackedLink(stackedProp); - expectNetworkState(wifiState); + NetworkState[] states = new NetworkState[] {wifiState}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_WIFI); + mService.forceUpdateIfaces(NETWORKS_WIFI, new VpnInfo[0], states, getActiveIface(states)); NetworkStats.Entry uidStats = new NetworkStats.Entry( TEST_IFACE, UID_BLUE, SET_DEFAULT, 0xF00D, 1024L, 8L, 512L, 4L, 0L); @@ -748,12 +744,12 @@ public class NetworkStatsServiceTest { public void testForegroundBackground() throws Exception { // pretend that network comes online expectDefaultSettings(); - expectNetworkState(buildWifiState()); + NetworkState[] states = new NetworkState[] {buildWifiState()}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_WIFI); + mService.forceUpdateIfaces(NETWORKS_WIFI, new VpnInfo[0], states, getActiveIface(states)); // create some initial traffic @@ -806,12 +802,12 @@ public class NetworkStatsServiceTest { public void testMetered() throws Exception { // pretend that network comes online expectDefaultSettings(); - expectNetworkState(buildWifiState(true /* isMetered */)); + NetworkState[] states = new NetworkState[] {buildWifiState(true /* isMetered */)}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_WIFI); + mService.forceUpdateIfaces(NETWORKS_WIFI, new VpnInfo[0], states, getActiveIface(states)); // create some initial traffic @@ -846,12 +842,13 @@ public class NetworkStatsServiceTest { public void testRoaming() throws Exception { // pretend that network comes online expectDefaultSettings(); - expectNetworkState(buildMobile3gState(IMSI_1, true /* isRoaming */)); + NetworkState[] states = + new NetworkState[] {buildMobile3gState(IMSI_1, true /* isRoaming */)}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_MOBILE); + mService.forceUpdateIfaces(NETWORKS_MOBILE, new VpnInfo[0], states, getActiveIface(states)); // Create some traffic @@ -885,12 +882,12 @@ public class NetworkStatsServiceTest { public void testTethering() throws Exception { // pretend first mobile network comes online expectDefaultSettings(); - expectNetworkState(buildMobile3gState(IMSI_1)); + NetworkState[] states = new NetworkState[] {buildMobile3gState(IMSI_1)}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_MOBILE); + mService.forceUpdateIfaces(NETWORKS_MOBILE, new VpnInfo[0], states, getActiveIface(states)); // create some tethering traffic @@ -928,12 +925,12 @@ public class NetworkStatsServiceTest { // pretend that wifi network comes online; service should ask about full // network state, and poll any existing interfaces before updating. expectDefaultSettings(); - expectNetworkState(buildWifiState()); + NetworkState[] states = new NetworkState[] {buildWifiState()}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_WIFI); + mService.forceUpdateIfaces(NETWORKS_WIFI, new VpnInfo[0], states, getActiveIface(states)); // verify service has empty history for wifi assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0); @@ -1081,11 +1078,11 @@ public class NetworkStatsServiceTest { expectBandwidthControlCheck(); } - private void expectNetworkState(NetworkState... state) throws Exception { - when(mConnManager.getAllNetworkState()).thenReturn(state); - - final LinkProperties linkProp = state.length > 0 ? state[0].linkProperties : null; - when(mConnManager.getActiveLinkProperties()).thenReturn(linkProp); + private String getActiveIface(NetworkState... states) throws Exception { + if (states == null || states.length == 0 || states[0].linkProperties == null) { + return null; + } + return states[0].linkProperties.getInterfaceName(); } private void expectNetworkStatsSummary(NetworkStats summary) throws Exception { @@ -1094,8 +1091,6 @@ public class NetworkStatsServiceTest { private void expectNetworkStatsSummary(NetworkStats summary, NetworkStats tetherStats) throws Exception { - when(mConnManager.getAllVpnInfo()).thenReturn(new VpnInfo[0]); - expectNetworkStatsTethering(STATS_PER_IFACE, tetherStats); expectNetworkStatsSummaryDev(summary.clone()); expectNetworkStatsSummaryXt(summary.clone()); From c0e7f75e704b284c297a7f3317ce944394b608b0 Mon Sep 17 00:00:00 2001 From: Varun Anand Date: Tue, 5 Mar 2019 19:23:50 +0000 Subject: [PATCH 2/3] Revert "Update VPN capabilities when its underlying network set is null." This reverts commit bfabfe0ab321f1d4c13fa02fbfa47ea34d463bee. Bug: 126245192 Reason for revert: This change can lead to a deadlock that was fixed in http://ag/6580635. However, platform PMs think that fixing this is risky enough as this is not a recent problem and has been in the field for 3/4 of the year. Note: The merged-in tag is used to avoid this change from getting merged into pi-dev-plus-aosp. This is to avoid merge conflicts since we mostly work in aosp/master which merges into pi-dev-plus-aosp. Change-Id: I3814bcec87efb059f50f00617406501aaeac3b4d Merged-In: Id0abc4d304bb096e92479a118168690ccce634ed --- .../android/server/ConnectivityService.java | 55 +-------- .../server/ConnectivityServiceTest.java | 115 +++--------------- .../android/server/connectivity/VpnTest.java | 12 +- 3 files changed, 26 insertions(+), 156 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 1c66c5a771..c9f9ab675a 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -867,8 +867,7 @@ public class ConnectivityService extends IConnectivityManager.Stub mPermissionMonitor = new PermissionMonitor(mContext, mNetd); - // Set up the listener for user state for creating user VPNs. - // Should run on mHandler to avoid any races. + //set up the listener for user state for creating user VPNs IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Intent.ACTION_USER_STARTED); intentFilter.addAction(Intent.ACTION_USER_STOPPED); @@ -876,11 +875,7 @@ public class ConnectivityService extends IConnectivityManager.Stub intentFilter.addAction(Intent.ACTION_USER_REMOVED); intentFilter.addAction(Intent.ACTION_USER_UNLOCKED); mContext.registerReceiverAsUser( - mUserIntentReceiver, - UserHandle.ALL, - intentFilter, - null /* broadcastPermission */, - mHandler); + mUserIntentReceiver, UserHandle.ALL, intentFilter, null, null); mContext.registerReceiverAsUser(mUserPresentReceiver, UserHandle.SYSTEM, new IntentFilter(Intent.ACTION_USER_PRESENT), null, null); @@ -3820,27 +3815,17 @@ public class ConnectivityService extends IConnectivityManager.Stub * handler thread through their agent, this is asynchronous. When the capabilities objects * are computed they will be up-to-date as they are computed synchronously from here and * this is running on the ConnectivityService thread. + * TODO : Fix this and call updateCapabilities inline to remove out-of-order events. */ private void updateAllVpnsCapabilities() { - Network defaultNetwork = getNetwork(getDefaultNetwork()); synchronized (mVpns) { for (int i = 0; i < mVpns.size(); i++) { final Vpn vpn = mVpns.valueAt(i); - NetworkCapabilities nc = vpn.updateCapabilities(defaultNetwork); - updateVpnCapabilities(vpn, nc); + vpn.updateCapabilities(); } } } - private void updateVpnCapabilities(Vpn vpn, @Nullable NetworkCapabilities nc) { - ensureRunningOnConnectivityServiceThread(); - NetworkAgentInfo vpnNai = getNetworkAgentInfoForNetId(vpn.getNetId()); - if (vpnNai == null || nc == null) { - return; - } - updateCapabilities(vpnNai.getCurrentScore(), vpnNai, nc); - } - @Override public boolean updateLockdownVpn() { if (Binder.getCallingUid() != Process.SYSTEM_UID) { @@ -4147,27 +4132,21 @@ public class ConnectivityService extends IConnectivityManager.Stub } private void onUserAdded(int userId) { - Network defaultNetwork = getNetwork(getDefaultNetwork()); synchronized (mVpns) { final int vpnsSize = mVpns.size(); for (int i = 0; i < vpnsSize; i++) { Vpn vpn = mVpns.valueAt(i); vpn.onUserAdded(userId); - NetworkCapabilities nc = vpn.updateCapabilities(defaultNetwork); - updateVpnCapabilities(vpn, nc); } } } private void onUserRemoved(int userId) { - Network defaultNetwork = getNetwork(getDefaultNetwork()); synchronized (mVpns) { final int vpnsSize = mVpns.size(); for (int i = 0; i < vpnsSize; i++) { Vpn vpn = mVpns.valueAt(i); vpn.onUserRemoved(userId); - NetworkCapabilities nc = vpn.updateCapabilities(defaultNetwork); - updateVpnCapabilities(vpn, nc); } } } @@ -4186,7 +4165,6 @@ public class ConnectivityService extends IConnectivityManager.Stub private BroadcastReceiver mUserIntentReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - ensureRunningOnConnectivityServiceThread(); final String action = intent.getAction(); final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL); if (userId == UserHandle.USER_NULL) return; @@ -4672,19 +4650,6 @@ public class ConnectivityService extends IConnectivityManager.Stub return getNetworkForRequest(mDefaultRequest.requestId); } - @Nullable - private Network getNetwork(@Nullable NetworkAgentInfo nai) { - return nai != null ? nai.network : null; - } - - private void ensureRunningOnConnectivityServiceThread() { - if (mHandler.getLooper().getThread() != Thread.currentThread()) { - throw new IllegalStateException( - "Not running on ConnectivityService thread: " - + Thread.currentThread().getName()); - } - } - private boolean isDefaultNetwork(NetworkAgentInfo nai) { return nai == getDefaultNetwork(); } @@ -5232,8 +5197,6 @@ public class ConnectivityService extends IConnectivityManager.Stub updateTcpBufferSizes(newNetwork); mDnsManager.setDefaultDnsSystemProperties(newNetwork.linkProperties.getDnsServers()); notifyIfacesChangedForNetworkStats(); - // Fix up the NetworkCapabilities of any VPNs that don't specify underlying networks. - updateAllVpnsCapabilities(); } private void processListenRequests(NetworkAgentInfo nai, boolean capabilitiesChanged) { @@ -5667,10 +5630,6 @@ public class ConnectivityService extends IConnectivityManager.Stub // doing. updateSignalStrengthThresholds(networkAgent, "CONNECT", null); - if (networkAgent.isVPN()) { - updateAllVpnsCapabilities(); - } - // Consider network even though it is not yet validated. final long now = SystemClock.elapsedRealtime(); rematchNetworkAndRequests(networkAgent, ReapUnvalidatedNetworks.REAP, now); @@ -5864,11 +5823,7 @@ public class ConnectivityService extends IConnectivityManager.Stub success = mVpns.get(user).setUnderlyingNetworks(networks); } if (success) { - mHandler.post(() -> { - // Update VPN's capabilities based on updated underlying network set. - updateAllVpnsCapabilities(); - notifyIfacesChangedForNetworkStats(); - }); + mHandler.post(() -> notifyIfacesChangedForNetworkStats()); } return success; } diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 0dcb21ab83..c2c627d06e 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -20,7 +20,6 @@ import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF; import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC; import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME; -import static android.net.ConnectivityManager.NETID_UNSET; import static android.net.ConnectivityManager.TYPE_ETHERNET; import static android.net.ConnectivityManager.TYPE_MOBILE; import static android.net.ConnectivityManager.TYPE_MOBILE_FOTA; @@ -776,14 +775,11 @@ public class ConnectivityServiceTest { public void setUids(Set uids) { mNetworkCapabilities.setUids(uids); - updateCapabilities(null /* defaultNetwork */); + updateCapabilities(); } @Override public int getNetId() { - if (mMockNetworkAgent == null) { - return NETID_UNSET; - } return mMockNetworkAgent.getNetwork().netId; } @@ -804,13 +800,12 @@ public class ConnectivityServiceTest { } @Override - public NetworkCapabilities updateCapabilities(Network defaultNetwork) { - if (!mConnected) return null; - super.updateCapabilities(defaultNetwork); - // Because super.updateCapabilities will update the capabilities of the agent but - // not the mock agent, the mock agent needs to know about them. + public void updateCapabilities() { + if (!mConnected) return; + super.updateCapabilities(); + // Because super.updateCapabilities will update the capabilities of the agent but not + // the mock agent, the mock agent needs to know about them. copyCapabilitiesToNetworkAgent(); - return new NetworkCapabilities(mNetworkCapabilities); } private void copyCapabilitiesToNetworkAgent() { @@ -4223,7 +4218,6 @@ public class ConnectivityServiceTest { mMockVpn.setUids(ranges); vpnNetworkAgent.connect(false); mMockVpn.connect(); - mMockVpn.setUnderlyingNetworks(new Network[0]); genericNetworkCallback.expectAvailableCallbacksUnvalidated(vpnNetworkAgent); genericNotVpnNetworkCallback.assertNoCallback(); @@ -4256,7 +4250,6 @@ public class ConnectivityServiceTest { ranges.add(new UidRange(uid, uid)); mMockVpn.setUids(ranges); - vpnNetworkAgent.setUids(ranges); genericNetworkCallback.expectAvailableCallbacksValidated(vpnNetworkAgent); genericNotVpnNetworkCallback.assertNoCallback(); @@ -4290,11 +4283,12 @@ public class ConnectivityServiceTest { } @Test - public void testVpnWithoutInternet() { + public void testVpnWithAndWithoutInternet() { final int uid = Process.myUid(); final TestNetworkCallback defaultCallback = new TestNetworkCallback(); mCm.registerDefaultNetworkCallback(defaultCallback); + defaultCallback.assertNoCallback(); mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(true); @@ -4316,30 +4310,11 @@ public class ConnectivityServiceTest { vpnNetworkAgent.disconnect(); defaultCallback.assertNoCallback(); - mCm.unregisterNetworkCallback(defaultCallback); - } - - @Test - public void testVpnWithInternet() { - final int uid = Process.myUid(); - - final TestNetworkCallback defaultCallback = new TestNetworkCallback(); - mCm.registerDefaultNetworkCallback(defaultCallback); - - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); - mWiFiNetworkAgent.connect(true); - - defaultCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent); - assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); - - MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN); - final ArraySet ranges = new ArraySet<>(); - ranges.add(new UidRange(uid, uid)); + vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN); mMockVpn.setNetworkAgent(vpnNetworkAgent); mMockVpn.setUids(ranges); vpnNetworkAgent.connect(true /* validated */, true /* hasInternet */); mMockVpn.connect(); - defaultCallback.expectAvailableThenValidatedCallbacks(vpnNetworkAgent); assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); @@ -4347,6 +4322,14 @@ public class ConnectivityServiceTest { defaultCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent); defaultCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent); + vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN); + ranges.clear(); + mMockVpn.setNetworkAgent(vpnNetworkAgent); + mMockVpn.setUids(ranges); + vpnNetworkAgent.connect(false /* validated */, true /* hasInternet */); + mMockVpn.connect(); + defaultCallback.assertNoCallback(); + mCm.unregisterNetworkCallback(defaultCallback); } @@ -4447,68 +4430,4 @@ public class ConnectivityServiceTest { mMockVpn.disconnect(); } - - @Test - public void testNullUnderlyingNetworks() { - final int uid = Process.myUid(); - - final TestNetworkCallback vpnNetworkCallback = new TestNetworkCallback(); - final NetworkRequest vpnNetworkRequest = new NetworkRequest.Builder() - .removeCapability(NET_CAPABILITY_NOT_VPN) - .addTransportType(TRANSPORT_VPN) - .build(); - NetworkCapabilities nc; - mCm.registerNetworkCallback(vpnNetworkRequest, vpnNetworkCallback); - vpnNetworkCallback.assertNoCallback(); - - final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN); - final ArraySet ranges = new ArraySet<>(); - ranges.add(new UidRange(uid, uid)); - mMockVpn.setNetworkAgent(vpnNetworkAgent); - mMockVpn.connect(); - mMockVpn.setUids(ranges); - vpnNetworkAgent.connect(true /* validated */, false /* hasInternet */); - - vpnNetworkCallback.expectAvailableThenValidatedCallbacks(vpnNetworkAgent); - nc = mCm.getNetworkCapabilities(vpnNetworkAgent.getNetwork()); - assertTrue(nc.hasTransport(TRANSPORT_VPN)); - assertFalse(nc.hasTransport(TRANSPORT_CELLULAR)); - assertFalse(nc.hasTransport(TRANSPORT_WIFI)); - // By default, VPN is set to track default network (i.e. its underlying networks is null). - // In case of no default network, VPN is considered metered. - assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_METERED)); - - // Connect to Cell; Cell is the default network. - mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); - mCellNetworkAgent.connect(true); - - vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN) - && caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI) - && !caps.hasCapability(NET_CAPABILITY_NOT_METERED), - vpnNetworkAgent); - - // Connect to WiFi; WiFi is the new default. - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); - mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED); - mWiFiNetworkAgent.connect(true); - - vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN) - && !caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI) - && caps.hasCapability(NET_CAPABILITY_NOT_METERED), - vpnNetworkAgent); - - // Disconnect Cell. The default network did not change, so there shouldn't be any changes in - // the capabilities. - mCellNetworkAgent.disconnect(); - - // Disconnect wifi too. Now we have no default network. - mWiFiNetworkAgent.disconnect(); - - vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN) - && !caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI) - && !caps.hasCapability(NET_CAPABILITY_NOT_METERED), - vpnNetworkAgent); - - mMockVpn.disconnect(); - } } diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java index a0a4ad1feb..e377a47253 100644 --- a/tests/net/java/com/android/server/connectivity/VpnTest.java +++ b/tests/net/java/com/android/server/connectivity/VpnTest.java @@ -457,8 +457,7 @@ public class VpnTest { final NetworkCapabilities caps = new NetworkCapabilities(); - Vpn.applyUnderlyingCapabilities( - mConnectivityManager, new Network[] {}, caps); + Vpn.updateCapabilities(mConnectivityManager, new Network[] { }, caps); assertTrue(caps.hasTransport(TRANSPORT_VPN)); assertFalse(caps.hasTransport(TRANSPORT_CELLULAR)); assertFalse(caps.hasTransport(TRANSPORT_WIFI)); @@ -468,8 +467,7 @@ public class VpnTest { assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING)); assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED)); - Vpn.applyUnderlyingCapabilities( - mConnectivityManager, new Network[] {mobile}, caps); + Vpn.updateCapabilities(mConnectivityManager, new Network[] { mobile }, caps); assertTrue(caps.hasTransport(TRANSPORT_VPN)); assertTrue(caps.hasTransport(TRANSPORT_CELLULAR)); assertFalse(caps.hasTransport(TRANSPORT_WIFI)); @@ -479,8 +477,7 @@ public class VpnTest { assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING)); assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED)); - Vpn.applyUnderlyingCapabilities( - mConnectivityManager, new Network[] {wifi}, caps); + Vpn.updateCapabilities(mConnectivityManager, new Network[] { wifi }, caps); assertTrue(caps.hasTransport(TRANSPORT_VPN)); assertFalse(caps.hasTransport(TRANSPORT_CELLULAR)); assertTrue(caps.hasTransport(TRANSPORT_WIFI)); @@ -490,8 +487,7 @@ public class VpnTest { assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING)); assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED)); - Vpn.applyUnderlyingCapabilities( - mConnectivityManager, new Network[] {mobile, wifi}, caps); + Vpn.updateCapabilities(mConnectivityManager, new Network[] { mobile, wifi }, caps); assertTrue(caps.hasTransport(TRANSPORT_VPN)); assertTrue(caps.hasTransport(TRANSPORT_CELLULAR)); assertTrue(caps.hasTransport(TRANSPORT_WIFI)); From bf1d84cc4e1fa4cca72ef53775fa7f8a6eba1e0e Mon Sep 17 00:00:00 2001 From: Varun Anand Date: Thu, 14 Mar 2019 18:28:00 +0000 Subject: [PATCH 3/3] Revert "Revert "Update VPN capabilities when its underlying network set is null."" This reverts commit c0e7f75e704b284c297a7f3317ce944394b608b0. Reason for revert: Retargeted for June monthly release Bug: 119129310 Change-Id: I9d543415c5707859cfa2a14a1a8ce5909aae7d11 Merged-In: Id0abc4d304bb096e92479a118168690ccce634ed --- .../android/server/ConnectivityService.java | 55 ++++++++- .../server/ConnectivityServiceTest.java | 115 +++++++++++++++--- .../android/server/connectivity/VpnTest.java | 12 +- 3 files changed, 156 insertions(+), 26 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index c9f9ab675a..1c66c5a771 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -867,7 +867,8 @@ public class ConnectivityService extends IConnectivityManager.Stub mPermissionMonitor = new PermissionMonitor(mContext, mNetd); - //set up the listener for user state for creating user VPNs + // Set up the listener for user state for creating user VPNs. + // Should run on mHandler to avoid any races. IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Intent.ACTION_USER_STARTED); intentFilter.addAction(Intent.ACTION_USER_STOPPED); @@ -875,7 +876,11 @@ public class ConnectivityService extends IConnectivityManager.Stub intentFilter.addAction(Intent.ACTION_USER_REMOVED); intentFilter.addAction(Intent.ACTION_USER_UNLOCKED); mContext.registerReceiverAsUser( - mUserIntentReceiver, UserHandle.ALL, intentFilter, null, null); + mUserIntentReceiver, + UserHandle.ALL, + intentFilter, + null /* broadcastPermission */, + mHandler); mContext.registerReceiverAsUser(mUserPresentReceiver, UserHandle.SYSTEM, new IntentFilter(Intent.ACTION_USER_PRESENT), null, null); @@ -3815,17 +3820,27 @@ public class ConnectivityService extends IConnectivityManager.Stub * handler thread through their agent, this is asynchronous. When the capabilities objects * are computed they will be up-to-date as they are computed synchronously from here and * this is running on the ConnectivityService thread. - * TODO : Fix this and call updateCapabilities inline to remove out-of-order events. */ private void updateAllVpnsCapabilities() { + Network defaultNetwork = getNetwork(getDefaultNetwork()); synchronized (mVpns) { for (int i = 0; i < mVpns.size(); i++) { final Vpn vpn = mVpns.valueAt(i); - vpn.updateCapabilities(); + NetworkCapabilities nc = vpn.updateCapabilities(defaultNetwork); + updateVpnCapabilities(vpn, nc); } } } + private void updateVpnCapabilities(Vpn vpn, @Nullable NetworkCapabilities nc) { + ensureRunningOnConnectivityServiceThread(); + NetworkAgentInfo vpnNai = getNetworkAgentInfoForNetId(vpn.getNetId()); + if (vpnNai == null || nc == null) { + return; + } + updateCapabilities(vpnNai.getCurrentScore(), vpnNai, nc); + } + @Override public boolean updateLockdownVpn() { if (Binder.getCallingUid() != Process.SYSTEM_UID) { @@ -4132,21 +4147,27 @@ public class ConnectivityService extends IConnectivityManager.Stub } private void onUserAdded(int userId) { + Network defaultNetwork = getNetwork(getDefaultNetwork()); synchronized (mVpns) { final int vpnsSize = mVpns.size(); for (int i = 0; i < vpnsSize; i++) { Vpn vpn = mVpns.valueAt(i); vpn.onUserAdded(userId); + NetworkCapabilities nc = vpn.updateCapabilities(defaultNetwork); + updateVpnCapabilities(vpn, nc); } } } private void onUserRemoved(int userId) { + Network defaultNetwork = getNetwork(getDefaultNetwork()); synchronized (mVpns) { final int vpnsSize = mVpns.size(); for (int i = 0; i < vpnsSize; i++) { Vpn vpn = mVpns.valueAt(i); vpn.onUserRemoved(userId); + NetworkCapabilities nc = vpn.updateCapabilities(defaultNetwork); + updateVpnCapabilities(vpn, nc); } } } @@ -4165,6 +4186,7 @@ public class ConnectivityService extends IConnectivityManager.Stub private BroadcastReceiver mUserIntentReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { + ensureRunningOnConnectivityServiceThread(); final String action = intent.getAction(); final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL); if (userId == UserHandle.USER_NULL) return; @@ -4650,6 +4672,19 @@ public class ConnectivityService extends IConnectivityManager.Stub return getNetworkForRequest(mDefaultRequest.requestId); } + @Nullable + private Network getNetwork(@Nullable NetworkAgentInfo nai) { + return nai != null ? nai.network : null; + } + + private void ensureRunningOnConnectivityServiceThread() { + if (mHandler.getLooper().getThread() != Thread.currentThread()) { + throw new IllegalStateException( + "Not running on ConnectivityService thread: " + + Thread.currentThread().getName()); + } + } + private boolean isDefaultNetwork(NetworkAgentInfo nai) { return nai == getDefaultNetwork(); } @@ -5197,6 +5232,8 @@ public class ConnectivityService extends IConnectivityManager.Stub updateTcpBufferSizes(newNetwork); mDnsManager.setDefaultDnsSystemProperties(newNetwork.linkProperties.getDnsServers()); notifyIfacesChangedForNetworkStats(); + // Fix up the NetworkCapabilities of any VPNs that don't specify underlying networks. + updateAllVpnsCapabilities(); } private void processListenRequests(NetworkAgentInfo nai, boolean capabilitiesChanged) { @@ -5630,6 +5667,10 @@ public class ConnectivityService extends IConnectivityManager.Stub // doing. updateSignalStrengthThresholds(networkAgent, "CONNECT", null); + if (networkAgent.isVPN()) { + updateAllVpnsCapabilities(); + } + // Consider network even though it is not yet validated. final long now = SystemClock.elapsedRealtime(); rematchNetworkAndRequests(networkAgent, ReapUnvalidatedNetworks.REAP, now); @@ -5823,7 +5864,11 @@ public class ConnectivityService extends IConnectivityManager.Stub success = mVpns.get(user).setUnderlyingNetworks(networks); } if (success) { - mHandler.post(() -> notifyIfacesChangedForNetworkStats()); + mHandler.post(() -> { + // Update VPN's capabilities based on updated underlying network set. + updateAllVpnsCapabilities(); + notifyIfacesChangedForNetworkStats(); + }); } return success; } diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index c2c627d06e..0dcb21ab83 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -20,6 +20,7 @@ import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF; import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC; import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME; +import static android.net.ConnectivityManager.NETID_UNSET; import static android.net.ConnectivityManager.TYPE_ETHERNET; import static android.net.ConnectivityManager.TYPE_MOBILE; import static android.net.ConnectivityManager.TYPE_MOBILE_FOTA; @@ -775,11 +776,14 @@ public class ConnectivityServiceTest { public void setUids(Set uids) { mNetworkCapabilities.setUids(uids); - updateCapabilities(); + updateCapabilities(null /* defaultNetwork */); } @Override public int getNetId() { + if (mMockNetworkAgent == null) { + return NETID_UNSET; + } return mMockNetworkAgent.getNetwork().netId; } @@ -800,12 +804,13 @@ public class ConnectivityServiceTest { } @Override - public void updateCapabilities() { - if (!mConnected) return; - super.updateCapabilities(); - // Because super.updateCapabilities will update the capabilities of the agent but not - // the mock agent, the mock agent needs to know about them. + public NetworkCapabilities updateCapabilities(Network defaultNetwork) { + if (!mConnected) return null; + super.updateCapabilities(defaultNetwork); + // Because super.updateCapabilities will update the capabilities of the agent but + // not the mock agent, the mock agent needs to know about them. copyCapabilitiesToNetworkAgent(); + return new NetworkCapabilities(mNetworkCapabilities); } private void copyCapabilitiesToNetworkAgent() { @@ -4218,6 +4223,7 @@ public class ConnectivityServiceTest { mMockVpn.setUids(ranges); vpnNetworkAgent.connect(false); mMockVpn.connect(); + mMockVpn.setUnderlyingNetworks(new Network[0]); genericNetworkCallback.expectAvailableCallbacksUnvalidated(vpnNetworkAgent); genericNotVpnNetworkCallback.assertNoCallback(); @@ -4250,6 +4256,7 @@ public class ConnectivityServiceTest { ranges.add(new UidRange(uid, uid)); mMockVpn.setUids(ranges); + vpnNetworkAgent.setUids(ranges); genericNetworkCallback.expectAvailableCallbacksValidated(vpnNetworkAgent); genericNotVpnNetworkCallback.assertNoCallback(); @@ -4283,12 +4290,11 @@ public class ConnectivityServiceTest { } @Test - public void testVpnWithAndWithoutInternet() { + public void testVpnWithoutInternet() { final int uid = Process.myUid(); final TestNetworkCallback defaultCallback = new TestNetworkCallback(); mCm.registerDefaultNetworkCallback(defaultCallback); - defaultCallback.assertNoCallback(); mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(true); @@ -4310,11 +4316,30 @@ public class ConnectivityServiceTest { vpnNetworkAgent.disconnect(); defaultCallback.assertNoCallback(); - vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN); + mCm.unregisterNetworkCallback(defaultCallback); + } + + @Test + public void testVpnWithInternet() { + final int uid = Process.myUid(); + + final TestNetworkCallback defaultCallback = new TestNetworkCallback(); + mCm.registerDefaultNetworkCallback(defaultCallback); + + mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent.connect(true); + + defaultCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent); + assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); + + MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN); + final ArraySet ranges = new ArraySet<>(); + ranges.add(new UidRange(uid, uid)); mMockVpn.setNetworkAgent(vpnNetworkAgent); mMockVpn.setUids(ranges); vpnNetworkAgent.connect(true /* validated */, true /* hasInternet */); mMockVpn.connect(); + defaultCallback.expectAvailableThenValidatedCallbacks(vpnNetworkAgent); assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); @@ -4322,14 +4347,6 @@ public class ConnectivityServiceTest { defaultCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent); defaultCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent); - vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN); - ranges.clear(); - mMockVpn.setNetworkAgent(vpnNetworkAgent); - mMockVpn.setUids(ranges); - vpnNetworkAgent.connect(false /* validated */, true /* hasInternet */); - mMockVpn.connect(); - defaultCallback.assertNoCallback(); - mCm.unregisterNetworkCallback(defaultCallback); } @@ -4430,4 +4447,68 @@ public class ConnectivityServiceTest { mMockVpn.disconnect(); } + + @Test + public void testNullUnderlyingNetworks() { + final int uid = Process.myUid(); + + final TestNetworkCallback vpnNetworkCallback = new TestNetworkCallback(); + final NetworkRequest vpnNetworkRequest = new NetworkRequest.Builder() + .removeCapability(NET_CAPABILITY_NOT_VPN) + .addTransportType(TRANSPORT_VPN) + .build(); + NetworkCapabilities nc; + mCm.registerNetworkCallback(vpnNetworkRequest, vpnNetworkCallback); + vpnNetworkCallback.assertNoCallback(); + + final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN); + final ArraySet ranges = new ArraySet<>(); + ranges.add(new UidRange(uid, uid)); + mMockVpn.setNetworkAgent(vpnNetworkAgent); + mMockVpn.connect(); + mMockVpn.setUids(ranges); + vpnNetworkAgent.connect(true /* validated */, false /* hasInternet */); + + vpnNetworkCallback.expectAvailableThenValidatedCallbacks(vpnNetworkAgent); + nc = mCm.getNetworkCapabilities(vpnNetworkAgent.getNetwork()); + assertTrue(nc.hasTransport(TRANSPORT_VPN)); + assertFalse(nc.hasTransport(TRANSPORT_CELLULAR)); + assertFalse(nc.hasTransport(TRANSPORT_WIFI)); + // By default, VPN is set to track default network (i.e. its underlying networks is null). + // In case of no default network, VPN is considered metered. + assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_METERED)); + + // Connect to Cell; Cell is the default network. + mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); + mCellNetworkAgent.connect(true); + + vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN) + && caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI) + && !caps.hasCapability(NET_CAPABILITY_NOT_METERED), + vpnNetworkAgent); + + // Connect to WiFi; WiFi is the new default. + mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED); + mWiFiNetworkAgent.connect(true); + + vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN) + && !caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI) + && caps.hasCapability(NET_CAPABILITY_NOT_METERED), + vpnNetworkAgent); + + // Disconnect Cell. The default network did not change, so there shouldn't be any changes in + // the capabilities. + mCellNetworkAgent.disconnect(); + + // Disconnect wifi too. Now we have no default network. + mWiFiNetworkAgent.disconnect(); + + vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN) + && !caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI) + && !caps.hasCapability(NET_CAPABILITY_NOT_METERED), + vpnNetworkAgent); + + mMockVpn.disconnect(); + } } diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java index e377a47253..a0a4ad1feb 100644 --- a/tests/net/java/com/android/server/connectivity/VpnTest.java +++ b/tests/net/java/com/android/server/connectivity/VpnTest.java @@ -457,7 +457,8 @@ public class VpnTest { final NetworkCapabilities caps = new NetworkCapabilities(); - Vpn.updateCapabilities(mConnectivityManager, new Network[] { }, caps); + Vpn.applyUnderlyingCapabilities( + mConnectivityManager, new Network[] {}, caps); assertTrue(caps.hasTransport(TRANSPORT_VPN)); assertFalse(caps.hasTransport(TRANSPORT_CELLULAR)); assertFalse(caps.hasTransport(TRANSPORT_WIFI)); @@ -467,7 +468,8 @@ public class VpnTest { assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING)); assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED)); - Vpn.updateCapabilities(mConnectivityManager, new Network[] { mobile }, caps); + Vpn.applyUnderlyingCapabilities( + mConnectivityManager, new Network[] {mobile}, caps); assertTrue(caps.hasTransport(TRANSPORT_VPN)); assertTrue(caps.hasTransport(TRANSPORT_CELLULAR)); assertFalse(caps.hasTransport(TRANSPORT_WIFI)); @@ -477,7 +479,8 @@ public class VpnTest { assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING)); assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED)); - Vpn.updateCapabilities(mConnectivityManager, new Network[] { wifi }, caps); + Vpn.applyUnderlyingCapabilities( + mConnectivityManager, new Network[] {wifi}, caps); assertTrue(caps.hasTransport(TRANSPORT_VPN)); assertFalse(caps.hasTransport(TRANSPORT_CELLULAR)); assertTrue(caps.hasTransport(TRANSPORT_WIFI)); @@ -487,7 +490,8 @@ public class VpnTest { assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING)); assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED)); - Vpn.updateCapabilities(mConnectivityManager, new Network[] { mobile, wifi }, caps); + Vpn.applyUnderlyingCapabilities( + mConnectivityManager, new Network[] {mobile, wifi}, caps); assertTrue(caps.hasTransport(TRANSPORT_VPN)); assertTrue(caps.hasTransport(TRANSPORT_CELLULAR)); assertTrue(caps.hasTransport(TRANSPORT_WIFI));