Update VPN capabilities when its underlying network set is null.

Previously, they were only updated when underlying network set was
non-null.

This change also ensures that all the calls b/w ConnectivityService and
Vpn that leads to updating capabilities are on ConnectivityService
handler thread.

Additionally, it also ensures that capabilities are propagated after VPN
enters connected state. This was previously done from establish which
could potentially lead to race between VPN getting connected and
capabilities getting updated.

This change also updates VPN capabilities inline from
ConnectivityService handler thread. Previously, there was an additional
loop where Vpn would update capabilities via NetworkAgent thru
AsyncChannel which posts back to CS handler thread, which could
potentially lead to delays in updating VPN capabilities.

Bug: 119129310
Bug: 118856062
Bug: 124268198
Test: atest FrameworksNetTests
Test: manual - verified VPNs capabilities are getting updated and
DownloadManager is working correctly.

Change-Id: Id0abc4d304bb096e92479a118168690ccce634ed
This commit is contained in:
Varun Anand
2019-02-06 10:13:38 -08:00
parent 2f96229cbd
commit df56995870
3 changed files with 158 additions and 28 deletions

View File

@@ -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;
@@ -885,11 +886,14 @@ public class ConnectivityServiceTest {
public void setUids(Set<UidRange> uids) {
mNetworkCapabilities.setUids(uids);
updateCapabilities();
updateCapabilities(null /* defaultNetwork */);
}
@Override
public int getNetId() {
if (mMockNetworkAgent == null) {
return NETID_UNSET;
}
return mMockNetworkAgent.getNetwork().netId;
}
@@ -911,12 +915,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() {
@@ -4660,6 +4665,7 @@ public class ConnectivityServiceTest {
vpnNetworkAgent.connect(false);
mMockVpn.connect();
mMockVpn.setUnderlyingNetworks(new Network[0]);
genericNetworkCallback.expectAvailableCallbacksUnvalidated(vpnNetworkAgent);
genericNotVpnNetworkCallback.assertNoCallback();
@@ -4692,6 +4698,7 @@ public class ConnectivityServiceTest {
ranges.add(new UidRange(uid, uid));
mMockVpn.setUids(ranges);
vpnNetworkAgent.setUids(ranges);
genericNetworkCallback.expectAvailableCallbacksValidated(vpnNetworkAgent);
genericNotVpnNetworkCallback.assertNoCallback();
@@ -4725,12 +4732,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);
@@ -4752,11 +4758,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<UidRange> 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());
@@ -4764,14 +4789,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);
}
@@ -4873,6 +4890,70 @@ 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<UidRange> 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();
}
@Test
public void testNetworkBlockedStatus() {
final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();

View File

@@ -566,7 +566,7 @@ public class VpnTest {
final NetworkCapabilities caps = new NetworkCapabilities();
Vpn.updateCapabilities(
Vpn.applyUnderlyingCapabilities(
mConnectivityManager, new Network[] {}, caps, false /* isAlwaysMetered */);
assertTrue(caps.hasTransport(TRANSPORT_VPN));
assertFalse(caps.hasTransport(TRANSPORT_CELLULAR));
@@ -577,7 +577,7 @@ public class VpnTest {
assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
Vpn.updateCapabilities(
Vpn.applyUnderlyingCapabilities(
mConnectivityManager,
new Network[] {mobile},
caps,
@@ -591,7 +591,7 @@ public class VpnTest {
assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
Vpn.updateCapabilities(
Vpn.applyUnderlyingCapabilities(
mConnectivityManager, new Network[] {wifi}, caps, false /* isAlwaysMetered */);
assertTrue(caps.hasTransport(TRANSPORT_VPN));
assertFalse(caps.hasTransport(TRANSPORT_CELLULAR));
@@ -602,7 +602,7 @@ public class VpnTest {
assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
Vpn.updateCapabilities(
Vpn.applyUnderlyingCapabilities(
mConnectivityManager, new Network[] {wifi}, caps, true /* isAlwaysMetered */);
assertTrue(caps.hasTransport(TRANSPORT_VPN));
assertFalse(caps.hasTransport(TRANSPORT_CELLULAR));
@@ -613,7 +613,7 @@ public class VpnTest {
assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
Vpn.updateCapabilities(
Vpn.applyUnderlyingCapabilities(
mConnectivityManager,
new Network[] {mobile, wifi},
caps,