Merge "Track default upstream when system is ready"

This commit is contained in:
Mark Chien
2018-12-13 13:28:08 +00:00
committed by Gerrit Code Review
5 changed files with 99 additions and 86 deletions

View File

@@ -1968,6 +1968,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
void systemReady() { void systemReady() {
mProxyTracker.loadGlobalProxy(); mProxyTracker.loadGlobalProxy();
registerNetdEventCallback(); registerNetdEventCallback();
mTethering.systemReady();
synchronized (this) { synchronized (this) {
mSystemReady = true; mSystemReady = true;

View File

@@ -1382,7 +1382,7 @@ public class Tethering extends BaseNetworkObserver {
return; return;
} }
mUpstreamNetworkMonitor.start(mDeps.getDefaultNetworkRequest()); mUpstreamNetworkMonitor.startObserveAllNetworks();
// TODO: De-duplicate with updateUpstreamWanted() below. // TODO: De-duplicate with updateUpstreamWanted() below.
if (upstreamWanted()) { if (upstreamWanted()) {
@@ -1658,6 +1658,10 @@ public class Tethering extends BaseNetworkObserver {
} }
} }
public void systemReady() {
mUpstreamNetworkMonitor.startTrackDefaultNetwork(mDeps.getDefaultNetworkRequest());
}
@Override @Override
public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
// Binder.java closes the resource for us. // Binder.java closes the resource for us.

View File

@@ -55,10 +55,13 @@ import java.util.Set;
* A class to centralize all the network and link properties information * A class to centralize all the network and link properties information
* pertaining to the current and any potential upstream network. * pertaining to the current and any potential upstream network.
* *
* Calling #start() registers two callbacks: one to track the system default * The owner of UNM gets it to register network callbacks by calling the
* network and a second to observe all networks. The latter is necessary * following methods :
* while the expression of preferred upstreams remains a list of legacy * Calling #startTrackDefaultNetwork() to track the system default network.
* connectivity types. In future, this can be revisited. * Calling #startObserveAllNetworks() to observe all networks. Listening all
* networks is necessary while the expression of preferred upstreams remains
* a list of legacy connectivity types. In future, this can be revisited.
* Calling #registerMobileNetworkRequest() to bring up mobile DUN/HIPRI network.
* *
* The methods and data members of this class are only to be accessed and * The methods and data members of this class are only to be accessed and
* modified from the tethering master state machine thread. Any other * modified from the tethering master state machine thread. Any other
@@ -119,33 +122,31 @@ public class UpstreamNetworkMonitor {
mCM = cm; mCM = cm;
} }
public void start(NetworkRequest defaultNetworkRequest) { public void startTrackDefaultNetwork(NetworkRequest defaultNetworkRequest) {
stop(); // This is not really a "request", just a way of tracking the system default network.
// It's guaranteed not to actually bring up any networks because it's the same request
final NetworkRequest listenAllRequest = new NetworkRequest.Builder() // as the ConnectivityService default request, and thus shares fate with it. We can't
.clearCapabilities().build(); // use registerDefaultNetworkCallback because it will not track the system default
mListenAllCallback = new UpstreamNetworkCallback(CALLBACK_LISTEN_ALL); // network if there is a VPN that applies to our UID.
cm().registerNetworkCallback(listenAllRequest, mListenAllCallback, mHandler); if (mDefaultNetworkCallback == null) {
if (defaultNetworkRequest != null) {
// This is not really a "request", just a way of tracking the system default network.
// It's guaranteed not to actually bring up any networks because it's the same request
// as the ConnectivityService default request, and thus shares fate with it. We can't
// use registerDefaultNetworkCallback because it will not track the system default
// network if there is a VPN that applies to our UID.
final NetworkRequest trackDefaultRequest = new NetworkRequest(defaultNetworkRequest); final NetworkRequest trackDefaultRequest = new NetworkRequest(defaultNetworkRequest);
mDefaultNetworkCallback = new UpstreamNetworkCallback(CALLBACK_DEFAULT_INTERNET); mDefaultNetworkCallback = new UpstreamNetworkCallback(CALLBACK_DEFAULT_INTERNET);
cm().requestNetwork(trackDefaultRequest, mDefaultNetworkCallback, mHandler); cm().requestNetwork(trackDefaultRequest, mDefaultNetworkCallback, mHandler);
} }
} }
public void startObserveAllNetworks() {
stop();
final NetworkRequest listenAllRequest = new NetworkRequest.Builder()
.clearCapabilities().build();
mListenAllCallback = new UpstreamNetworkCallback(CALLBACK_LISTEN_ALL);
cm().registerNetworkCallback(listenAllRequest, mListenAllCallback, mHandler);
}
public void stop() { public void stop() {
releaseMobileNetworkRequest(); releaseMobileNetworkRequest();
releaseCallback(mDefaultNetworkCallback);
mDefaultNetworkCallback = null;
mDefaultInternetNetwork = null;
releaseCallback(mListenAllCallback); releaseCallback(mListenAllCallback);
mListenAllCallback = null; mListenAllCallback = null;
@@ -264,9 +265,7 @@ public class UpstreamNetworkMonitor {
mNetworkMap.put(network, new NetworkState(null, null, null, network, null, null)); mNetworkMap.put(network, new NetworkState(null, null, null, network, null, null));
} }
private void handleNetCap(int callbackType, Network network, NetworkCapabilities newNc) { private void handleNetCap(Network network, NetworkCapabilities newNc) {
if (callbackType == CALLBACK_DEFAULT_INTERNET) mDefaultInternetNetwork = network;
final NetworkState prev = mNetworkMap.get(network); final NetworkState prev = mNetworkMap.get(network);
if (prev == null || newNc.equals(prev.networkCapabilities)) { if (prev == null || newNc.equals(prev.networkCapabilities)) {
// Ignore notifications about networks for which we have not yet // Ignore notifications about networks for which we have not yet
@@ -315,31 +314,25 @@ public class UpstreamNetworkMonitor {
notifyTarget(EVENT_ON_LINKPROPERTIES, network); notifyTarget(EVENT_ON_LINKPROPERTIES, network);
} }
private void handleSuspended(int callbackType, Network network) { private void handleSuspended(Network network) {
if (callbackType != CALLBACK_LISTEN_ALL) return;
if (!network.equals(mTetheringUpstreamNetwork)) return; if (!network.equals(mTetheringUpstreamNetwork)) return;
mLog.log("SUSPENDED current upstream: " + network); mLog.log("SUSPENDED current upstream: " + network);
} }
private void handleResumed(int callbackType, Network network) { private void handleResumed(Network network) {
if (callbackType != CALLBACK_LISTEN_ALL) return;
if (!network.equals(mTetheringUpstreamNetwork)) return; if (!network.equals(mTetheringUpstreamNetwork)) return;
mLog.log("RESUMED current upstream: " + network); mLog.log("RESUMED current upstream: " + network);
} }
private void handleLost(int callbackType, Network network) { private void handleLost(Network network) {
if (network.equals(mDefaultInternetNetwork)) { // There are few TODOs within ConnectivityService's rematching code
mDefaultInternetNetwork = null; // pertaining to spurious onLost() notifications.
// There are few TODOs within ConnectivityService's rematching code //
// pertaining to spurious onLost() notifications. // TODO: simplify this, probably if favor of code that:
// // - selects a new upstream if mTetheringUpstreamNetwork has
// TODO: simplify this, probably if favor of code that: // been lost (by any callback)
// - selects a new upstream if mTetheringUpstreamNetwork has // - deletes the entry from the map only when the LISTEN_ALL
// been lost (by any callback) // callback gets notified.
// - deletes the entry from the map only when the LISTEN_ALL
// callback gets notified.
if (callbackType == CALLBACK_DEFAULT_INTERNET) return;
}
if (!mNetworkMap.containsKey(network)) { if (!mNetworkMap.containsKey(network)) {
// Ignore loss of networks about which we had not previously // Ignore loss of networks about which we had not previously
@@ -393,11 +386,17 @@ public class UpstreamNetworkMonitor {
@Override @Override
public void onCapabilitiesChanged(Network network, NetworkCapabilities newNc) { public void onCapabilitiesChanged(Network network, NetworkCapabilities newNc) {
handleNetCap(mCallbackType, network, newNc); if (mCallbackType == CALLBACK_DEFAULT_INTERNET) {
mDefaultInternetNetwork = network;
return;
}
handleNetCap(network, newNc);
} }
@Override @Override
public void onLinkPropertiesChanged(Network network, LinkProperties newLp) { public void onLinkPropertiesChanged(Network network, LinkProperties newLp) {
if (mCallbackType == CALLBACK_DEFAULT_INTERNET) return;
handleLinkProp(network, newLp); handleLinkProp(network, newLp);
// Any non-LISTEN_ALL callback will necessarily concern a network that will // Any non-LISTEN_ALL callback will necessarily concern a network that will
// also match the LISTEN_ALL callback by construction of the LISTEN_ALL callback. // also match the LISTEN_ALL callback by construction of the LISTEN_ALL callback.
@@ -409,17 +408,25 @@ public class UpstreamNetworkMonitor {
@Override @Override
public void onNetworkSuspended(Network network) { public void onNetworkSuspended(Network network) {
handleSuspended(mCallbackType, network); if (mCallbackType == CALLBACK_LISTEN_ALL) {
handleSuspended(network);
}
} }
@Override @Override
public void onNetworkResumed(Network network) { public void onNetworkResumed(Network network) {
handleResumed(mCallbackType, network); if (mCallbackType == CALLBACK_LISTEN_ALL) {
handleResumed(network);
}
} }
@Override @Override
public void onLost(Network network) { public void onLost(Network network) {
handleLost(mCallbackType, network); if (mCallbackType == CALLBACK_DEFAULT_INTERNET) {
mDefaultInternetNetwork = null;
return;
}
handleLost(network);
// Any non-LISTEN_ALL callback will necessarily concern a network that will // Any non-LISTEN_ALL callback will necessarily concern a network that will
// also match the LISTEN_ALL callback by construction of the LISTEN_ALL callback. // also match the LISTEN_ALL callback by construction of the LISTEN_ALL callback.
// So it's not useful to do this work for non-LISTEN_ALL callbacks. // So it's not useful to do this work for non-LISTEN_ALL callbacks.

View File

@@ -71,7 +71,6 @@ import android.net.MacAddress;
import android.net.Network; import android.net.Network;
import android.net.NetworkCapabilities; import android.net.NetworkCapabilities;
import android.net.NetworkInfo; import android.net.NetworkInfo;
import android.net.NetworkRequest;
import android.net.NetworkState; import android.net.NetworkState;
import android.net.NetworkUtils; import android.net.NetworkUtils;
import android.net.RouteInfo; import android.net.RouteInfo;
@@ -130,10 +129,6 @@ public class TetheringTest {
private static final String TEST_USB_IFNAME = "test_rndis0"; private static final String TEST_USB_IFNAME = "test_rndis0";
private static final String TEST_WLAN_IFNAME = "test_wlan0"; private static final String TEST_WLAN_IFNAME = "test_wlan0";
// Actual contents of the request don't matter for this test. The lack of
// any specific TRANSPORT_* is sufficient to identify this request.
private static final NetworkRequest mDefaultRequest = new NetworkRequest.Builder().build();
@Mock private ApplicationInfo mApplicationInfo; @Mock private ApplicationInfo mApplicationInfo;
@Mock private Context mContext; @Mock private Context mContext;
@Mock private INetworkManagementService mNMService; @Mock private INetworkManagementService mNMService;
@@ -257,11 +252,6 @@ public class TetheringTest {
isTetheringSupportedCalls++; isTetheringSupportedCalls++;
return true; return true;
} }
@Override
public NetworkRequest getDefaultNetworkRequest() {
return mDefaultRequest;
}
} }
private static NetworkState buildMobileUpstreamState(boolean withIPv4, boolean withIPv6, private static NetworkState buildMobileUpstreamState(boolean withIPv4, boolean withIPv6,
@@ -496,7 +486,7 @@ public class TetheringTest {
TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_LOCAL_ONLY); TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_LOCAL_ONLY);
verifyNoMoreInteractions(mWifiManager); verifyNoMoreInteractions(mWifiManager);
verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_ACTIVE_LOCAL_ONLY); verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_ACTIVE_LOCAL_ONLY);
verify(mUpstreamNetworkMonitor, times(1)).start(any(NetworkRequest.class)); verify(mUpstreamNetworkMonitor, times(1)).startObserveAllNetworks();
// TODO: Figure out why this isn't exactly once, for sendTetherStateChangedBroadcast(). // TODO: Figure out why this isn't exactly once, for sendTetherStateChangedBroadcast().
assertTrue(1 <= mTetheringDependencies.isTetheringSupportedCalls); assertTrue(1 <= mTetheringDependencies.isTetheringSupportedCalls);
@@ -730,7 +720,7 @@ public class TetheringTest {
TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_TETHERED); TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_TETHERED);
verifyNoMoreInteractions(mWifiManager); verifyNoMoreInteractions(mWifiManager);
verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_ACTIVE_TETHER); verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_ACTIVE_TETHER);
verify(mUpstreamNetworkMonitor, times(1)).start(any(NetworkRequest.class)); verify(mUpstreamNetworkMonitor, times(1)).startObserveAllNetworks();
// In tethering mode, in the default configuration, an explicit request // In tethering mode, in the default configuration, an explicit request
// for a mobile network is also made. // for a mobile network is also made.
verify(mUpstreamNetworkMonitor, times(1)).registerMobileNetworkRequest(); verify(mUpstreamNetworkMonitor, times(1)).registerMobileNetworkRequest();

View File

@@ -24,6 +24,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
@@ -53,7 +54,6 @@ import android.net.NetworkCapabilities;
import android.net.NetworkRequest; import android.net.NetworkRequest;
import android.net.NetworkState; import android.net.NetworkState;
import android.net.util.SharedLog; import android.net.util.SharedLog;
import android.support.test.filters.SmallTest; import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4; import android.support.test.runner.AndroidJUnit4;
@@ -65,7 +65,6 @@ import org.junit.Before;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.junit.Test; import org.junit.Test;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
import java.util.ArrayList; import java.util.ArrayList;
@@ -126,7 +125,7 @@ public class UpstreamNetworkMonitorTest {
} }
@Test @Test
public void testDoesNothingBeforeStarted() { public void testDoesNothingBeforeTrackDefaultAndStarted() throws Exception {
assertTrue(mCM.hasNoCallbacks()); assertTrue(mCM.hasNoCallbacks());
assertFalse(mUNM.mobileNetworkRequested()); assertFalse(mUNM.mobileNetworkRequested());
@@ -138,37 +137,40 @@ public class UpstreamNetworkMonitorTest {
@Test @Test
public void testDefaultNetworkIsTracked() throws Exception { public void testDefaultNetworkIsTracked() throws Exception {
assertEquals(0, mCM.trackingDefault.size()); assertTrue(mCM.hasNoCallbacks());
mUNM.startTrackDefaultNetwork(mDefaultRequest);
mUNM.start(mDefaultRequest); mUNM.startObserveAllNetworks();
assertEquals(1, mCM.trackingDefault.size()); assertEquals(1, mCM.trackingDefault.size());
mUNM.stop(); mUNM.stop();
assertTrue(mCM.hasNoCallbacks()); assertTrue(mCM.onlyHasDefaultCallbacks());
} }
@Test @Test
public void testListensForAllNetworks() throws Exception { public void testListensForAllNetworks() throws Exception {
assertTrue(mCM.listening.isEmpty()); assertTrue(mCM.listening.isEmpty());
mUNM.start(mDefaultRequest); mUNM.startTrackDefaultNetwork(mDefaultRequest);
mUNM.startObserveAllNetworks();
assertFalse(mCM.listening.isEmpty()); assertFalse(mCM.listening.isEmpty());
assertTrue(mCM.isListeningForAll()); assertTrue(mCM.isListeningForAll());
mUNM.stop(); mUNM.stop();
assertTrue(mCM.hasNoCallbacks()); assertTrue(mCM.onlyHasDefaultCallbacks());
} }
@Test @Test
public void testCallbacksRegistered() { public void testCallbacksRegistered() {
mUNM.start(mDefaultRequest); mUNM.startTrackDefaultNetwork(mDefaultRequest);
verify(mCM, times(1)).registerNetworkCallback(
any(NetworkRequest.class), any(NetworkCallback.class), any(Handler.class));
verify(mCM, times(1)).requestNetwork( verify(mCM, times(1)).requestNetwork(
eq(mDefaultRequest), any(NetworkCallback.class), any(Handler.class)); eq(mDefaultRequest), any(NetworkCallback.class), any(Handler.class));
mUNM.startObserveAllNetworks();
verify(mCM, times(1)).registerNetworkCallback(
any(NetworkRequest.class), any(NetworkCallback.class), any(Handler.class));
mUNM.stop(); mUNM.stop();
verify(mCM, times(2)).unregisterNetworkCallback(any(NetworkCallback.class)); verify(mCM, times(1)).unregisterNetworkCallback(any(NetworkCallback.class));
} }
@Test @Test
@@ -176,7 +178,7 @@ public class UpstreamNetworkMonitorTest {
assertFalse(mUNM.mobileNetworkRequested()); assertFalse(mUNM.mobileNetworkRequested());
assertEquals(0, mCM.requested.size()); assertEquals(0, mCM.requested.size());
mUNM.start(mDefaultRequest); mUNM.startObserveAllNetworks();
assertFalse(mUNM.mobileNetworkRequested()); assertFalse(mUNM.mobileNetworkRequested());
assertEquals(0, mCM.requested.size()); assertEquals(0, mCM.requested.size());
@@ -199,11 +201,9 @@ public class UpstreamNetworkMonitorTest {
assertFalse(mUNM.mobileNetworkRequested()); assertFalse(mUNM.mobileNetworkRequested());
assertEquals(0, mCM.requested.size()); assertEquals(0, mCM.requested.size());
mUNM.start(mDefaultRequest); mUNM.startObserveAllNetworks();
verify(mCM, times(1)).registerNetworkCallback( verify(mCM, times(1)).registerNetworkCallback(
any(NetworkRequest.class), any(NetworkCallback.class), any(Handler.class)); any(NetworkRequest.class), any(NetworkCallback.class), any(Handler.class));
verify(mCM, times(1)).requestNetwork(
eq(mDefaultRequest), any(NetworkCallback.class), any(Handler.class));
assertFalse(mUNM.mobileNetworkRequested()); assertFalse(mUNM.mobileNetworkRequested());
assertEquals(0, mCM.requested.size()); assertEquals(0, mCM.requested.size());
@@ -227,7 +227,7 @@ public class UpstreamNetworkMonitorTest {
assertTrue(mCM.isDunRequested()); assertTrue(mCM.isDunRequested());
mUNM.stop(); mUNM.stop();
verify(mCM, times(3)).unregisterNetworkCallback(any(NetworkCallback.class)); verify(mCM, times(2)).unregisterNetworkCallback(any(NetworkCallback.class));
verifyNoMoreInteractions(mCM); verifyNoMoreInteractions(mCM);
} }
@@ -237,7 +237,7 @@ public class UpstreamNetworkMonitorTest {
assertFalse(mUNM.mobileNetworkRequested()); assertFalse(mUNM.mobileNetworkRequested());
assertEquals(0, mCM.requested.size()); assertEquals(0, mCM.requested.size());
mUNM.start(mDefaultRequest); mUNM.startObserveAllNetworks();
assertFalse(mUNM.mobileNetworkRequested()); assertFalse(mUNM.mobileNetworkRequested());
assertEquals(0, mCM.requested.size()); assertEquals(0, mCM.requested.size());
@@ -257,7 +257,7 @@ public class UpstreamNetworkMonitorTest {
@Test @Test
public void testUpdateMobileRequiresDun() throws Exception { public void testUpdateMobileRequiresDun() throws Exception {
mUNM.start(mDefaultRequest); mUNM.startObserveAllNetworks();
// Test going from no-DUN to DUN correctly re-registers callbacks. // Test going from no-DUN to DUN correctly re-registers callbacks.
mUNM.updateMobileRequiresDun(false); mUNM.updateMobileRequiresDun(false);
@@ -285,7 +285,8 @@ public class UpstreamNetworkMonitorTest {
final Collection<Integer> preferredTypes = new ArrayList<>(); final Collection<Integer> preferredTypes = new ArrayList<>();
preferredTypes.add(TYPE_WIFI); preferredTypes.add(TYPE_WIFI);
mUNM.start(mDefaultRequest); mUNM.startTrackDefaultNetwork(mDefaultRequest);
mUNM.startObserveAllNetworks();
// There are no networks, so there is nothing to select. // There are no networks, so there is nothing to select.
assertSatisfiesLegacyType(TYPE_NONE, mUNM.selectPreferredUpstreamType(preferredTypes)); assertSatisfiesLegacyType(TYPE_NONE, mUNM.selectPreferredUpstreamType(preferredTypes));
@@ -350,7 +351,8 @@ public class UpstreamNetworkMonitorTest {
@Test @Test
public void testGetCurrentPreferredUpstream() throws Exception { public void testGetCurrentPreferredUpstream() throws Exception {
mUNM.start(mDefaultRequest); mUNM.startTrackDefaultNetwork(mDefaultRequest);
mUNM.startObserveAllNetworks();
mUNM.updateMobileRequiresDun(false); mUNM.updateMobileRequiresDun(false);
// [0] Mobile connects, DUN not required -> mobile selected. // [0] Mobile connects, DUN not required -> mobile selected.
@@ -389,7 +391,8 @@ public class UpstreamNetworkMonitorTest {
@Test @Test
public void testLocalPrefixes() throws Exception { public void testLocalPrefixes() throws Exception {
mUNM.start(mDefaultRequest); mUNM.startTrackDefaultNetwork(mDefaultRequest);
mUNM.startObserveAllNetworks();
// [0] Test minimum set of local prefixes. // [0] Test minimum set of local prefixes.
Set<IpPrefix> local = mUNM.getLocalPrefixes(); Set<IpPrefix> local = mUNM.getLocalPrefixes();
@@ -521,11 +524,19 @@ public class UpstreamNetworkMonitorTest {
} }
boolean hasNoCallbacks() { boolean hasNoCallbacks() {
return allCallbacks.isEmpty() && return allCallbacks.isEmpty()
trackingDefault.isEmpty() && && trackingDefault.isEmpty()
listening.isEmpty() && && listening.isEmpty()
requested.isEmpty() && && requested.isEmpty()
legacyTypeMap.isEmpty(); && legacyTypeMap.isEmpty();
}
boolean onlyHasDefaultCallbacks() {
return (allCallbacks.size() == 1)
&& (trackingDefault.size() == 1)
&& listening.isEmpty()
&& requested.isEmpty()
&& legacyTypeMap.isEmpty();
} }
boolean isListeningForAll() { boolean isListeningForAll() {