Merge "Move findPreferredUpstreamType into UNM"

This commit is contained in:
Treehugger Robot
2017-06-08 12:02:59 +00:00
committed by Gerrit Code Review
4 changed files with 181 additions and 55 deletions

View File

@@ -1232,8 +1232,8 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
protected void chooseUpstreamType(boolean tryCell) {
updateConfiguration(); // TODO - remove?
final int upstreamType = findPreferredUpstreamType(
getConnectivityManager(), mConfig);
final int upstreamType = mUpstreamNetworkMonitor.selectPreferredUpstreamType(
mConfig.preferredUpstreamIfaceTypes);
if (upstreamType == ConnectivityManager.TYPE_NONE) {
if (tryCell) {
mUpstreamNetworkMonitor.registerMobileNetworkRequest();
@@ -1245,58 +1245,6 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
setUpstreamByType(upstreamType);
}
// TODO: Move this function into UpstreamNetworkMonitor.
protected int findPreferredUpstreamType(ConnectivityManager cm,
TetheringConfiguration cfg) {
int upType = ConnectivityManager.TYPE_NONE;
if (VDBG) {
Log.d(TAG, "chooseUpstreamType has upstream iface types:");
for (Integer netType : cfg.preferredUpstreamIfaceTypes) {
Log.d(TAG, " " + netType);
}
}
for (Integer netType : cfg.preferredUpstreamIfaceTypes) {
NetworkInfo info = cm.getNetworkInfo(netType.intValue());
// TODO: if the network is suspended we should consider
// that to be the same as connected here.
if ((info != null) && info.isConnected()) {
upType = netType.intValue();
break;
}
}
final int preferredUpstreamMobileApn = cfg.isDunRequired
? ConnectivityManager.TYPE_MOBILE_DUN
: ConnectivityManager.TYPE_MOBILE_HIPRI;
mLog.log(String.format(
"findPreferredUpstreamType(), preferredApn=%s, got type=%s",
getNetworkTypeName(preferredUpstreamMobileApn),
getNetworkTypeName(upType)));
switch (upType) {
case ConnectivityManager.TYPE_MOBILE_DUN:
case ConnectivityManager.TYPE_MOBILE_HIPRI:
// If we're on DUN, put our own grab on it.
mUpstreamNetworkMonitor.registerMobileNetworkRequest();
break;
case ConnectivityManager.TYPE_NONE:
break;
default:
/* If we've found an active upstream connection that's not DUN/HIPRI
* we should stop any outstanding DUN/HIPRI start requests.
*
* If we found NONE we don't want to do this as we want any previous
* requests to keep trying to bring up something we can use.
*/
mUpstreamNetworkMonitor.releaseMobileNetworkRequest();
break;
}
return upType;
}
protected void setUpstreamByType(int upType) {
final ConnectivityManager cm = getConnectivityManager();
Network network = null;

View File

@@ -16,6 +16,8 @@
package com.android.server.connectivity.tethering;
import static android.net.ConnectivityManager.getNetworkTypeName;
import static android.net.ConnectivityManager.TYPE_NONE;
import static android.net.ConnectivityManager.TYPE_MOBILE_DUN;
import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI;
@@ -176,6 +178,41 @@ public class UpstreamNetworkMonitor {
return (network != null) ? mNetworkMap.get(network) : null;
}
// So many TODOs here, but chief among them is: make this functionality an
// integral part of this class such that whenever a higher priority network
// becomes available and useful we (a) file a request to keep it up as
// necessary and (b) change all upstream tracking state accordingly (by
// passing LinkProperties up to Tethering).
//
// Next TODO: return NetworkState instead of just the type.
public int selectPreferredUpstreamType(Iterable<Integer> preferredTypes) {
final TypeStatePair typeStatePair = findFirstAvailableUpstreamByType(
mNetworkMap.values(), preferredTypes);
mLog.log("preferred upstream type: " + getNetworkTypeName(typeStatePair.type));
switch (typeStatePair.type) {
case TYPE_MOBILE_DUN:
case TYPE_MOBILE_HIPRI:
// If we're on DUN, put our own grab on it.
registerMobileNetworkRequest();
break;
case TYPE_NONE:
break;
default:
/* If we've found an active upstream connection that's not DUN/HIPRI
* we should stop any outstanding DUN/HIPRI start requests.
*
* If we found NONE we don't want to do this as we want any previous
* requests to keep trying to bring up something we can use.
*/
releaseMobileNetworkRequest();
break;
}
return typeStatePair.type;
}
private void handleAvailable(int callbackType, Network network) {
if (VDBG) Log.d(TAG, "EVENT_ON_AVAILABLE for " + network);
@@ -365,4 +402,37 @@ public class UpstreamNetworkMonitor {
private void notifyTarget(int which, NetworkState netstate) {
mTarget.sendMessage(mWhat, which, 0, netstate);
}
static private class TypeStatePair {
public int type = TYPE_NONE;
public NetworkState ns = null;
}
static private TypeStatePair findFirstAvailableUpstreamByType(
Iterable<NetworkState> netStates, Iterable<Integer> preferredTypes) {
final TypeStatePair result = new TypeStatePair();
for (int type : preferredTypes) {
NetworkCapabilities nc;
try {
nc = ConnectivityManager.networkCapabilitiesForType(type);
} catch (IllegalArgumentException iae) {
Log.e(TAG, "No NetworkCapabilities mapping for legacy type: " +
ConnectivityManager.getNetworkTypeName(type));
continue;
}
for (NetworkState value : netStates) {
if (!nc.satisfiedByNetworkCapabilities(value.networkCapabilities)) {
continue;
}
result.type = type;
result.ns = value;
return result;
}
}
return result;
}
}

View File

@@ -368,7 +368,6 @@ public class TetheringTest {
any(NetworkCallback.class), any(Handler.class));
// In tethering mode, in the default configuration, an explicit request
// for a mobile network is also made.
verify(mConnectivityManager, atLeastOnce()).getNetworkInfo(anyInt());
verify(mConnectivityManager, times(1)).requestNetwork(
any(NetworkRequest.class), any(NetworkCallback.class), eq(0), anyInt(),
any(Handler.class));

View File

@@ -18,7 +18,12 @@ package com.android.server.connectivity.tethering;
import static android.net.ConnectivityManager.TYPE_MOBILE_DUN;
import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI;
import static android.net.ConnectivityManager.TYPE_NONE;
import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -59,6 +64,7 @@ import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
@@ -240,6 +246,72 @@ public class UpstreamNetworkMonitorTest {
assertFalse(mUNM.mobileNetworkRequested());
}
@Test
public void testSelectPreferredUpstreamType() throws Exception {
final Collection<Integer> preferredTypes = new ArrayList<>();
preferredTypes.add(TYPE_WIFI);
mUNM.start();
// There are no networks, so there is nothing to select.
assertEquals(TYPE_NONE, mUNM.selectPreferredUpstreamType(preferredTypes));
final TestNetworkAgent wifiAgent = new TestNetworkAgent(mCM, TRANSPORT_WIFI);
wifiAgent.fakeConnect();
// WiFi is up, we should prefer it.
assertEquals(TYPE_WIFI, mUNM.selectPreferredUpstreamType(preferredTypes));
wifiAgent.fakeDisconnect();
// There are no networks, so there is nothing to select.
assertEquals(TYPE_NONE, mUNM.selectPreferredUpstreamType(preferredTypes));
final TestNetworkAgent cellAgent = new TestNetworkAgent(mCM, TRANSPORT_CELLULAR);
cellAgent.fakeConnect();
assertEquals(TYPE_NONE, mUNM.selectPreferredUpstreamType(preferredTypes));
preferredTypes.add(TYPE_MOBILE_DUN);
// This is coupled with preferred types in TetheringConfiguration.
mUNM.updateMobileRequiresDun(true);
// DUN is available, but only use regular cell: no upstream selected.
assertEquals(TYPE_NONE, mUNM.selectPreferredUpstreamType(preferredTypes));
preferredTypes.remove(TYPE_MOBILE_DUN);
// No WiFi, but our preferred flavour of cell is up.
preferredTypes.add(TYPE_MOBILE_HIPRI);
// This is coupled with preferred types in TetheringConfiguration.
mUNM.updateMobileRequiresDun(false);
assertEquals(TYPE_MOBILE_HIPRI, mUNM.selectPreferredUpstreamType(preferredTypes));
// Check to see we filed an explicit request.
assertEquals(1, mCM.requested.size());
NetworkRequest netReq = (NetworkRequest) mCM.requested.values().toArray()[0];
assertTrue(netReq.networkCapabilities.hasTransport(TRANSPORT_CELLULAR));
assertFalse(netReq.networkCapabilities.hasCapability(NET_CAPABILITY_DUN));
wifiAgent.fakeConnect();
// WiFi is up, and we should prefer it over cell.
assertEquals(TYPE_WIFI, mUNM.selectPreferredUpstreamType(preferredTypes));
assertEquals(0, mCM.requested.size());
preferredTypes.remove(TYPE_MOBILE_HIPRI);
preferredTypes.add(TYPE_MOBILE_DUN);
// This is coupled with preferred types in TetheringConfiguration.
mUNM.updateMobileRequiresDun(true);
assertEquals(TYPE_WIFI, mUNM.selectPreferredUpstreamType(preferredTypes));
final TestNetworkAgent dunAgent = new TestNetworkAgent(mCM, TRANSPORT_CELLULAR);
dunAgent.networkCapabilities.addCapability(NET_CAPABILITY_DUN);
dunAgent.fakeConnect();
// WiFi is still preferred.
assertEquals(TYPE_WIFI, mUNM.selectPreferredUpstreamType(preferredTypes));
// WiFi goes down, cell and DUN are still up but only DUN is preferred.
wifiAgent.fakeDisconnect();
assertEquals(TYPE_MOBILE_DUN, mUNM.selectPreferredUpstreamType(preferredTypes));
// Check to see we filed an explicit request.
assertEquals(1, mCM.requested.size());
netReq = (NetworkRequest) mCM.requested.values().toArray()[0];
assertTrue(netReq.networkCapabilities.hasTransport(TRANSPORT_CELLULAR));
assertTrue(netReq.networkCapabilities.hasCapability(NET_CAPABILITY_DUN));
}
private void assertUpstreamTypeRequested(int upstreamType) throws Exception {
assertEquals(1, mCM.requested.size());
assertEquals(1, mCM.legacyTypeMap.size());
@@ -254,6 +326,8 @@ public class UpstreamNetworkMonitorTest {
public Map<NetworkCallback, NetworkRequest> requested = new HashMap<>();
public Map<NetworkCallback, Integer> legacyTypeMap = new HashMap<>();
private int mNetworkId = 100;
public TestConnectivityManager(Context ctx, IConnectivityManager svc) {
super(ctx, svc);
}
@@ -287,6 +361,8 @@ public class UpstreamNetworkMonitorTest {
return false;
}
int getNetworkId() { return ++mNetworkId; }
@Override
public void requestNetwork(NetworkRequest req, NetworkCallback cb, Handler h) {
assertFalse(allCallbacks.containsKey(cb));
@@ -360,6 +436,35 @@ public class UpstreamNetworkMonitorTest {
}
}
public static class TestNetworkAgent {
public final TestConnectivityManager cm;
public final Network networkId;
public final int transportType;
public final NetworkCapabilities networkCapabilities;
public TestNetworkAgent(TestConnectivityManager cm, int transportType) {
this.cm = cm;
this.networkId = new Network(cm.getNetworkId());
this.transportType = transportType;
networkCapabilities = new NetworkCapabilities();
networkCapabilities.addTransportType(transportType);
networkCapabilities.addCapability(NET_CAPABILITY_INTERNET);
}
public void fakeConnect() {
for (NetworkCallback cb : cm.listening.keySet()) {
cb.onAvailable(networkId);
cb.onCapabilitiesChanged(networkId, copy(networkCapabilities));
}
}
public void fakeDisconnect() {
for (NetworkCallback cb : cm.listening.keySet()) {
cb.onLost(networkId);
}
}
}
public static class TestStateMachine extends StateMachine {
public final ArrayList<Message> messages = new ArrayList<>();
private final State mLoggingState = new LoggingState();
@@ -382,4 +487,8 @@ public class UpstreamNetworkMonitorTest {
super.start();
}
}
static NetworkCapabilities copy(NetworkCapabilities nc) {
return new NetworkCapabilities(nc);
}
}