Revert "Revert "Update VPN capabilities when its underlying network set is null.""

This reverts commit c0e7f75e70.

Reason for revert: Retargeted for June monthly release

Bug: 119129310

Change-Id: I9d543415c5707859cfa2a14a1a8ce5909aae7d11
Merged-In: Id0abc4d304bb096e92479a118168690ccce634ed
This commit is contained in:
Varun Anand
2019-03-14 18:28:00 +00:00
parent c0e7f75e70
commit bf1d84cc4e
3 changed files with 156 additions and 26 deletions

View File

@@ -867,7 +867,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
mPermissionMonitor = new PermissionMonitor(mContext, mNetd); 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 intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_USER_STARTED); intentFilter.addAction(Intent.ACTION_USER_STARTED);
intentFilter.addAction(Intent.ACTION_USER_STOPPED); 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_REMOVED);
intentFilter.addAction(Intent.ACTION_USER_UNLOCKED); intentFilter.addAction(Intent.ACTION_USER_UNLOCKED);
mContext.registerReceiverAsUser( mContext.registerReceiverAsUser(
mUserIntentReceiver, UserHandle.ALL, intentFilter, null, null); mUserIntentReceiver,
UserHandle.ALL,
intentFilter,
null /* broadcastPermission */,
mHandler);
mContext.registerReceiverAsUser(mUserPresentReceiver, UserHandle.SYSTEM, mContext.registerReceiverAsUser(mUserPresentReceiver, UserHandle.SYSTEM,
new IntentFilter(Intent.ACTION_USER_PRESENT), null, null); 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 * 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 * are computed they will be up-to-date as they are computed synchronously from here and
* this is running on the ConnectivityService thread. * this is running on the ConnectivityService thread.
* TODO : Fix this and call updateCapabilities inline to remove out-of-order events.
*/ */
private void updateAllVpnsCapabilities() { private void updateAllVpnsCapabilities() {
Network defaultNetwork = getNetwork(getDefaultNetwork());
synchronized (mVpns) { synchronized (mVpns) {
for (int i = 0; i < mVpns.size(); i++) { for (int i = 0; i < mVpns.size(); i++) {
final Vpn vpn = mVpns.valueAt(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 @Override
public boolean updateLockdownVpn() { public boolean updateLockdownVpn() {
if (Binder.getCallingUid() != Process.SYSTEM_UID) { if (Binder.getCallingUid() != Process.SYSTEM_UID) {
@@ -4132,21 +4147,27 @@ public class ConnectivityService extends IConnectivityManager.Stub
} }
private void onUserAdded(int userId) { private void onUserAdded(int userId) {
Network defaultNetwork = getNetwork(getDefaultNetwork());
synchronized (mVpns) { synchronized (mVpns) {
final int vpnsSize = mVpns.size(); final int vpnsSize = mVpns.size();
for (int i = 0; i < vpnsSize; i++) { for (int i = 0; i < vpnsSize; i++) {
Vpn vpn = mVpns.valueAt(i); Vpn vpn = mVpns.valueAt(i);
vpn.onUserAdded(userId); vpn.onUserAdded(userId);
NetworkCapabilities nc = vpn.updateCapabilities(defaultNetwork);
updateVpnCapabilities(vpn, nc);
} }
} }
} }
private void onUserRemoved(int userId) { private void onUserRemoved(int userId) {
Network defaultNetwork = getNetwork(getDefaultNetwork());
synchronized (mVpns) { synchronized (mVpns) {
final int vpnsSize = mVpns.size(); final int vpnsSize = mVpns.size();
for (int i = 0; i < vpnsSize; i++) { for (int i = 0; i < vpnsSize; i++) {
Vpn vpn = mVpns.valueAt(i); Vpn vpn = mVpns.valueAt(i);
vpn.onUserRemoved(userId); 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() { private BroadcastReceiver mUserIntentReceiver = new BroadcastReceiver() {
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
ensureRunningOnConnectivityServiceThread();
final String action = intent.getAction(); final String action = intent.getAction();
final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL); final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
if (userId == UserHandle.USER_NULL) return; if (userId == UserHandle.USER_NULL) return;
@@ -4650,6 +4672,19 @@ public class ConnectivityService extends IConnectivityManager.Stub
return getNetworkForRequest(mDefaultRequest.requestId); 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) { private boolean isDefaultNetwork(NetworkAgentInfo nai) {
return nai == getDefaultNetwork(); return nai == getDefaultNetwork();
} }
@@ -5197,6 +5232,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
updateTcpBufferSizes(newNetwork); updateTcpBufferSizes(newNetwork);
mDnsManager.setDefaultDnsSystemProperties(newNetwork.linkProperties.getDnsServers()); mDnsManager.setDefaultDnsSystemProperties(newNetwork.linkProperties.getDnsServers());
notifyIfacesChangedForNetworkStats(); notifyIfacesChangedForNetworkStats();
// Fix up the NetworkCapabilities of any VPNs that don't specify underlying networks.
updateAllVpnsCapabilities();
} }
private void processListenRequests(NetworkAgentInfo nai, boolean capabilitiesChanged) { private void processListenRequests(NetworkAgentInfo nai, boolean capabilitiesChanged) {
@@ -5630,6 +5667,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
// doing. // doing.
updateSignalStrengthThresholds(networkAgent, "CONNECT", null); updateSignalStrengthThresholds(networkAgent, "CONNECT", null);
if (networkAgent.isVPN()) {
updateAllVpnsCapabilities();
}
// Consider network even though it is not yet validated. // Consider network even though it is not yet validated.
final long now = SystemClock.elapsedRealtime(); final long now = SystemClock.elapsedRealtime();
rematchNetworkAndRequests(networkAgent, ReapUnvalidatedNetworks.REAP, now); rematchNetworkAndRequests(networkAgent, ReapUnvalidatedNetworks.REAP, now);
@@ -5823,7 +5864,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
success = mVpns.get(user).setUnderlyingNetworks(networks); success = mVpns.get(user).setUnderlyingNetworks(networks);
} }
if (success) { if (success) {
mHandler.post(() -> notifyIfacesChangedForNetworkStats()); mHandler.post(() -> {
// Update VPN's capabilities based on updated underlying network set.
updateAllVpnsCapabilities();
notifyIfacesChangedForNetworkStats();
});
} }
return success; return success;
} }

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_OFF;
import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC; import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME; 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_ETHERNET;
import static android.net.ConnectivityManager.TYPE_MOBILE; import static android.net.ConnectivityManager.TYPE_MOBILE;
import static android.net.ConnectivityManager.TYPE_MOBILE_FOTA; import static android.net.ConnectivityManager.TYPE_MOBILE_FOTA;
@@ -775,11 +776,14 @@ public class ConnectivityServiceTest {
public void setUids(Set<UidRange> uids) { public void setUids(Set<UidRange> uids) {
mNetworkCapabilities.setUids(uids); mNetworkCapabilities.setUids(uids);
updateCapabilities(); updateCapabilities(null /* defaultNetwork */);
} }
@Override @Override
public int getNetId() { public int getNetId() {
if (mMockNetworkAgent == null) {
return NETID_UNSET;
}
return mMockNetworkAgent.getNetwork().netId; return mMockNetworkAgent.getNetwork().netId;
} }
@@ -800,12 +804,13 @@ public class ConnectivityServiceTest {
} }
@Override @Override
public void updateCapabilities() { public NetworkCapabilities updateCapabilities(Network defaultNetwork) {
if (!mConnected) return; if (!mConnected) return null;
super.updateCapabilities(); super.updateCapabilities(defaultNetwork);
// Because super.updateCapabilities will update the capabilities of the agent but not // Because super.updateCapabilities will update the capabilities of the agent but
// the mock agent, the mock agent needs to know about them. // not the mock agent, the mock agent needs to know about them.
copyCapabilitiesToNetworkAgent(); copyCapabilitiesToNetworkAgent();
return new NetworkCapabilities(mNetworkCapabilities);
} }
private void copyCapabilitiesToNetworkAgent() { private void copyCapabilitiesToNetworkAgent() {
@@ -4218,6 +4223,7 @@ public class ConnectivityServiceTest {
mMockVpn.setUids(ranges); mMockVpn.setUids(ranges);
vpnNetworkAgent.connect(false); vpnNetworkAgent.connect(false);
mMockVpn.connect(); mMockVpn.connect();
mMockVpn.setUnderlyingNetworks(new Network[0]);
genericNetworkCallback.expectAvailableCallbacksUnvalidated(vpnNetworkAgent); genericNetworkCallback.expectAvailableCallbacksUnvalidated(vpnNetworkAgent);
genericNotVpnNetworkCallback.assertNoCallback(); genericNotVpnNetworkCallback.assertNoCallback();
@@ -4250,6 +4256,7 @@ public class ConnectivityServiceTest {
ranges.add(new UidRange(uid, uid)); ranges.add(new UidRange(uid, uid));
mMockVpn.setUids(ranges); mMockVpn.setUids(ranges);
vpnNetworkAgent.setUids(ranges);
genericNetworkCallback.expectAvailableCallbacksValidated(vpnNetworkAgent); genericNetworkCallback.expectAvailableCallbacksValidated(vpnNetworkAgent);
genericNotVpnNetworkCallback.assertNoCallback(); genericNotVpnNetworkCallback.assertNoCallback();
@@ -4283,12 +4290,11 @@ public class ConnectivityServiceTest {
} }
@Test @Test
public void testVpnWithAndWithoutInternet() { public void testVpnWithoutInternet() {
final int uid = Process.myUid(); final int uid = Process.myUid();
final TestNetworkCallback defaultCallback = new TestNetworkCallback(); final TestNetworkCallback defaultCallback = new TestNetworkCallback();
mCm.registerDefaultNetworkCallback(defaultCallback); mCm.registerDefaultNetworkCallback(defaultCallback);
defaultCallback.assertNoCallback();
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true); mWiFiNetworkAgent.connect(true);
@@ -4310,11 +4316,30 @@ public class ConnectivityServiceTest {
vpnNetworkAgent.disconnect(); vpnNetworkAgent.disconnect();
defaultCallback.assertNoCallback(); 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.setNetworkAgent(vpnNetworkAgent);
mMockVpn.setUids(ranges); mMockVpn.setUids(ranges);
vpnNetworkAgent.connect(true /* validated */, true /* hasInternet */); vpnNetworkAgent.connect(true /* validated */, true /* hasInternet */);
mMockVpn.connect(); mMockVpn.connect();
defaultCallback.expectAvailableThenValidatedCallbacks(vpnNetworkAgent); defaultCallback.expectAvailableThenValidatedCallbacks(vpnNetworkAgent);
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
@@ -4322,14 +4347,6 @@ public class ConnectivityServiceTest {
defaultCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent); defaultCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
defaultCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent); 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); mCm.unregisterNetworkCallback(defaultCallback);
} }
@@ -4430,4 +4447,68 @@ public class ConnectivityServiceTest {
mMockVpn.disconnect(); 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();
}
} }

View File

@@ -457,7 +457,8 @@ public class VpnTest {
final NetworkCapabilities caps = new NetworkCapabilities(); final NetworkCapabilities caps = new NetworkCapabilities();
Vpn.updateCapabilities(mConnectivityManager, new Network[] { }, caps); Vpn.applyUnderlyingCapabilities(
mConnectivityManager, new Network[] {}, caps);
assertTrue(caps.hasTransport(TRANSPORT_VPN)); assertTrue(caps.hasTransport(TRANSPORT_VPN));
assertFalse(caps.hasTransport(TRANSPORT_CELLULAR)); assertFalse(caps.hasTransport(TRANSPORT_CELLULAR));
assertFalse(caps.hasTransport(TRANSPORT_WIFI)); 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_ROAMING));
assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED)); 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_VPN));
assertTrue(caps.hasTransport(TRANSPORT_CELLULAR)); assertTrue(caps.hasTransport(TRANSPORT_CELLULAR));
assertFalse(caps.hasTransport(TRANSPORT_WIFI)); assertFalse(caps.hasTransport(TRANSPORT_WIFI));
@@ -477,7 +479,8 @@ public class VpnTest {
assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING)); assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED)); 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)); assertTrue(caps.hasTransport(TRANSPORT_VPN));
assertFalse(caps.hasTransport(TRANSPORT_CELLULAR)); assertFalse(caps.hasTransport(TRANSPORT_CELLULAR));
assertTrue(caps.hasTransport(TRANSPORT_WIFI)); 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_ROAMING));
assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED)); 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_VPN));
assertTrue(caps.hasTransport(TRANSPORT_CELLULAR)); assertTrue(caps.hasTransport(TRANSPORT_CELLULAR));
assertTrue(caps.hasTransport(TRANSPORT_WIFI)); assertTrue(caps.hasTransport(TRANSPORT_WIFI));