Skip to content
This repository has been archived by the owner on Nov 1, 2020. It is now read-only.

Commit

Permalink
DO NOT MERGE: Add unit tests to ensure VPN meteredness
Browse files Browse the repository at this point in the history
These new tests ensure that VPNs report the meteredness of their
underlying networks correctly. The added test verifies VPN meteredness
for cases of metered and unmetered WiFi and Cell

Bug: 78644887
Test: This; ran on walleye-eng
Change-Id: I28bdc71a336bfd97f7908455d4781d774df44b87
(cherry picked from commit 66bc528)
  • Loading branch information
Benedict Wong authored and android-build-team Robot committed Jul 20, 2018
1 parent dcdeaf8 commit b4c5afe
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 21 deletions.
58 changes: 37 additions & 21 deletions services/core/java/com/android/server/ConnectivityService.java
Original file line number Diff line number Diff line change
Expand Up @@ -969,7 +969,7 @@ private Network[] getVpnUnderlyingNetworks(int uid) {
if (!mLockdownEnabled) {
int user = UserHandle.getUserId(uid);
synchronized (mVpns) {
Vpn vpn = mVpns.get(user);
Vpn vpn = getVpn(user);
if (vpn != null && vpn.appliesToUid(uid)) {
return vpn.getUnderlyingNetworks();
}
Expand Down Expand Up @@ -1017,7 +1017,7 @@ private boolean isNetworkWithLinkPropertiesBlocked(LinkProperties lp, int uid,
return false;
}
synchronized (mVpns) {
final Vpn vpn = mVpns.get(UserHandle.getUserId(uid));
final Vpn vpn = getVpn(UserHandle.getUserId(uid));
if (vpn != null && vpn.isBlockingUid(uid)) {
return true;
}
Expand Down Expand Up @@ -1094,7 +1094,7 @@ private Network getActiveNetworkForUidInternal(final int uid, boolean ignoreBloc
final int user = UserHandle.getUserId(uid);
int vpnNetId = NETID_UNSET;
synchronized (mVpns) {
final Vpn vpn = mVpns.get(user);
final Vpn vpn = getVpn(user);
if (vpn != null && vpn.appliesToUid(uid)) vpnNetId = vpn.getNetId();
}
NetworkAgentInfo nai;
Expand Down Expand Up @@ -1224,7 +1224,7 @@ public NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser(int userId) {

if (!mLockdownEnabled) {
synchronized (mVpns) {
Vpn vpn = mVpns.get(userId);
Vpn vpn = getVpn(userId);
if (vpn != null) {
Network[] networks = vpn.getUnderlyingNetworks();
if (networks != null) {
Expand Down Expand Up @@ -3424,7 +3424,7 @@ public boolean prepareVpn(@Nullable String oldPackage, @Nullable String newPacka
throwIfLockdownEnabled();

synchronized (mVpns) {
Vpn vpn = mVpns.get(userId);
Vpn vpn = getVpn(userId);
if (vpn != null) {
return vpn.prepare(oldPackage, newPackage);
} else {
Expand All @@ -3451,7 +3451,7 @@ public void setVpnPackageAuthorization(String packageName, int userId, boolean a
enforceCrossUserPermission(userId);

synchronized (mVpns) {
Vpn vpn = mVpns.get(userId);
Vpn vpn = getVpn(userId);
if (vpn != null) {
vpn.setPackageAuthorization(packageName, authorized);
}
Expand All @@ -3470,7 +3470,7 @@ public ParcelFileDescriptor establishVpn(VpnConfig config) {
throwIfLockdownEnabled();
int user = UserHandle.getUserId(Binder.getCallingUid());
synchronized (mVpns) {
return mVpns.get(user).establish(config);
return getVpn(user).establish(config);
}
}

Expand All @@ -3487,7 +3487,7 @@ public void startLegacyVpn(VpnProfile profile) {
}
int user = UserHandle.getUserId(Binder.getCallingUid());
synchronized (mVpns) {
mVpns.get(user).startLegacyVpn(profile, mKeyStore, egress);
getVpn(user).startLegacyVpn(profile, mKeyStore, egress);
}
}

Expand All @@ -3501,7 +3501,7 @@ public LegacyVpnInfo getLegacyVpnInfo(int userId) {
enforceCrossUserPermission(userId);

synchronized (mVpns) {
return mVpns.get(userId).getLegacyVpnInfo();
return getVpn(userId).getLegacyVpnInfo();
}
}

Expand Down Expand Up @@ -3565,7 +3565,7 @@ private VpnInfo createVpnInfo(Vpn vpn) {
public VpnConfig getVpnConfig(int userId) {
enforceCrossUserPermission(userId);
synchronized (mVpns) {
Vpn vpn = mVpns.get(userId);
Vpn vpn = getVpn(userId);
if (vpn != null) {
return vpn.getVpnConfig();
} else {
Expand Down Expand Up @@ -3599,7 +3599,7 @@ public boolean updateLockdownVpn() {
}
int user = UserHandle.getUserId(Binder.getCallingUid());
synchronized (mVpns) {
Vpn vpn = mVpns.get(user);
Vpn vpn = getVpn(user);
if (vpn == null) {
Slog.w(TAG, "VPN for user " + user + " not ready yet. Skipping lockdown");
return false;
Expand Down Expand Up @@ -3646,7 +3646,7 @@ private void throwIfLockdownEnabled() {
*/
private boolean startAlwaysOnVpn(int userId) {
synchronized (mVpns) {
Vpn vpn = mVpns.get(userId);
Vpn vpn = getVpn(userId);
if (vpn == null) {
// Shouldn't happen as all codepaths that point here should have checked the Vpn
// exists already.
Expand All @@ -3664,7 +3664,7 @@ public boolean isAlwaysOnVpnPackageSupported(int userId, String packageName) {
enforceCrossUserPermission(userId);

synchronized (mVpns) {
Vpn vpn = mVpns.get(userId);
Vpn vpn = getVpn(userId);
if (vpn == null) {
Slog.w(TAG, "User " + userId + " has no Vpn configuration");
return false;
Expand All @@ -3684,7 +3684,7 @@ public boolean setAlwaysOnVpnPackage(int userId, String packageName, boolean loc
}

synchronized (mVpns) {
Vpn vpn = mVpns.get(userId);
Vpn vpn = getVpn(userId);
if (vpn == null) {
Slog.w(TAG, "User " + userId + " has no Vpn configuration");
return false;
Expand All @@ -3706,7 +3706,7 @@ public String getAlwaysOnVpnPackage(int userId) {
enforceCrossUserPermission(userId);

synchronized (mVpns) {
Vpn vpn = mVpns.get(userId);
Vpn vpn = getVpn(userId);
if (vpn == null) {
Slog.w(TAG, "User " + userId + " has no Vpn configuration");
return null;
Expand Down Expand Up @@ -3852,22 +3852,38 @@ public void setAirplaneMode(boolean enable) {

private void onUserStart(int userId) {
synchronized (mVpns) {
Vpn userVpn = mVpns.get(userId);
Vpn userVpn = getVpn(userId);
if (userVpn != null) {
loge("Starting user already has a VPN");
return;
}
userVpn = new Vpn(mHandler.getLooper(), mContext, mNetd, userId);
mVpns.put(userId, userVpn);
setVpn(userId, userVpn);
}
if (mUserManager.getUserInfo(userId).isPrimary() && LockdownVpnTracker.isEnabled()) {
updateLockdownVpn();
}
}

/** @hide */
@VisibleForTesting
Vpn getVpn(int userId) {
synchronized (mVpns) {
return mVpns.get(userId);
}
}

/** @hide */
@VisibleForTesting
void setVpn(int userId, Vpn userVpn) {
synchronized (mVpns) {
mVpns.put(userId, userVpn);
}
}

private void onUserStop(int userId) {
synchronized (mVpns) {
Vpn userVpn = mVpns.get(userId);
Vpn userVpn = getVpn(userId);
if (userVpn == null) {
loge("Stopped user has no VPN");
return;
Expand Down Expand Up @@ -5439,7 +5455,7 @@ public boolean addVpnAddress(String address, int prefixLength) {
throwIfLockdownEnabled();
int user = UserHandle.getUserId(Binder.getCallingUid());
synchronized (mVpns) {
return mVpns.get(user).addAddress(address, prefixLength);
return getVpn(user).addAddress(address, prefixLength);
}
}

Expand All @@ -5448,7 +5464,7 @@ public boolean removeVpnAddress(String address, int prefixLength) {
throwIfLockdownEnabled();
int user = UserHandle.getUserId(Binder.getCallingUid());
synchronized (mVpns) {
return mVpns.get(user).removeAddress(address, prefixLength);
return getVpn(user).removeAddress(address, prefixLength);
}
}

Expand All @@ -5458,7 +5474,7 @@ public boolean setUnderlyingNetworksForVpn(Network[] networks) {
int user = UserHandle.getUserId(Binder.getCallingUid());
boolean success;
synchronized (mVpns) {
success = mVpns.get(user).setUnderlyingNetworks(networks);
success = getVpn(user).setUnderlyingNetworks(networks);
}
if (success) {
notifyIfacesChangedForNetworkStats();
Expand Down
87 changes: 87 additions & 0 deletions tests/net/java/com/android/server/ConnectivityServiceTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import static android.net.ConnectivityManager.TYPE_MOBILE_FOTA;
import static android.net.ConnectivityManager.TYPE_MOBILE_MMS;
import static android.net.ConnectivityManager.TYPE_NONE;
import static android.net.ConnectivityManager.TYPE_VPN;
import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.net.ConnectivityManager.getNetworkTypeName;
import static android.net.NetworkCapabilities.*;
Expand Down Expand Up @@ -102,6 +103,7 @@
import com.android.server.connectivity.NetworkAgentInfo;
import com.android.server.connectivity.NetworkMonitor;
import com.android.server.connectivity.NetworkMonitor.CaptivePortalProbeResult;
import com.android.server.connectivity.Vpn;
import com.android.server.net.NetworkPinner;
import com.android.server.net.NetworkPolicyManagerInternal;

Expand Down Expand Up @@ -333,6 +335,9 @@ private class MockNetworkAgent {
case TRANSPORT_WIFI_AWARE:
mScore = 20;
break;
case TRANSPORT_VPN:
mScore = 0;
break;
default:
throw new UnsupportedOperationException("unimplemented network type");
}
Expand Down Expand Up @@ -868,6 +873,8 @@ private static int transportToLegacyType(int transport) {
return TYPE_WIFI;
case TRANSPORT_CELLULAR:
return TYPE_MOBILE;
case TRANSPORT_VPN:
return TYPE_VPN;
default:
return TYPE_NONE;
}
Expand Down Expand Up @@ -3447,4 +3454,84 @@ private static <T> void assertException(Runnable block, Class<T> expected) {
return;
}
}

@SmallTest
public void testVpnNetworkMetered() {
final TestNetworkCallback callback = new TestNetworkCallback();
mCm.registerDefaultNetworkCallback(callback);

final NetworkRequest cellRequest = new NetworkRequest.Builder()
.addTransportType(TRANSPORT_CELLULAR).build();
final TestNetworkCallback cellCallback = new TestNetworkCallback();
mCm.registerNetworkCallback(cellRequest, cellCallback);

// Setup cellular
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
callback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
cellCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
verifyActiveNetwork(TRANSPORT_CELLULAR);

// Verify meteredness of cellular
assertTrue(mCm.isActiveNetworkMetered());

// Setup Wifi
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true);
callback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
cellCallback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
verifyActiveNetwork(TRANSPORT_WIFI);

// Verify meteredness of WiFi
assertTrue(mCm.isActiveNetworkMetered());

// Verify that setting unmetered on Wifi changes ActiveNetworkMetered
mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
callback.expectCapabilitiesWith(NET_CAPABILITY_NOT_METERED, mWiFiNetworkAgent);
assertFalse(mCm.isActiveNetworkMetered());

// Setup VPN
final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
vpnNetworkAgent.connect(true);

Vpn mockVpn = mock(Vpn.class);
when(mockVpn.appliesToUid(anyInt())).thenReturn(true);
when(mockVpn.getNetId()).thenReturn(vpnNetworkAgent.getNetwork().netId);

Vpn oldVpn = mService.getVpn(UserHandle.myUserId());
mService.setVpn(UserHandle.myUserId(), mockVpn);
assertEquals(vpnNetworkAgent.getNetwork(), mCm.getActiveNetwork());

// Verify meteredness of VPN on default network
when(mockVpn.getUnderlyingNetworks()).thenReturn(null);
assertFalse(mCm.isActiveNetworkMetered());
assertFalse(mCm.isActiveNetworkMeteredForUid(Process.myUid()));

// Verify meteredness of VPN on unmetered wifi
when(mockVpn.getUnderlyingNetworks())
.thenReturn(new Network[] {mWiFiNetworkAgent.getNetwork()});
assertFalse(mCm.isActiveNetworkMetered());
assertFalse(mCm.isActiveNetworkMeteredForUid(Process.myUid()));

// Set WiFi as metered, then check to see that it has been updated on the VPN
mWiFiNetworkAgent.removeCapability(NET_CAPABILITY_NOT_METERED);
callback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_METERED, mWiFiNetworkAgent);
assertTrue(mCm.isActiveNetworkMetered());
assertTrue(mCm.isActiveNetworkMeteredForUid(Process.myUid()));

// Switch to cellular
when(mockVpn.getUnderlyingNetworks())
.thenReturn(new Network[] {mCellNetworkAgent.getNetwork()});
assertTrue(mCm.isActiveNetworkMetered());
assertTrue(mCm.isActiveNetworkMeteredForUid(Process.myUid()));

// Test unmetered cellular
mCellNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
cellCallback.expectCapabilitiesWith(NET_CAPABILITY_NOT_METERED, mCellNetworkAgent);
assertFalse(mCm.isActiveNetworkMetered());
assertFalse(mCm.isActiveNetworkMeteredForUid(Process.myUid()));

mService.setVpn(UserHandle.myUserId(), oldVpn);
mCm.unregisterNetworkCallback(callback);
}
}

0 comments on commit b4c5afe

Please sign in to comment.