Merge "Make interface IP serving code set LinkProperties" am: 1dae9a4709
am: 9461f78541
Change-Id: I753ab701f2109c0972816724e73119dc1dbc4dca
This commit is contained in:
@@ -1268,10 +1268,10 @@ public class Tethering extends BaseNetworkObserver {
|
|||||||
sendMessageDelayed(CMD_RETRY_UPSTREAM, UPSTREAM_SETTLE_TIME_MS);
|
sendMessageDelayed(CMD_RETRY_UPSTREAM, UPSTREAM_SETTLE_TIME_MS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setUpstreamByType(ns);
|
setUpstreamNetwork(ns);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void setUpstreamByType(NetworkState ns) {
|
protected void setUpstreamNetwork(NetworkState ns) {
|
||||||
String iface = null;
|
String iface = null;
|
||||||
if (ns != null && ns.linkProperties != null) {
|
if (ns != null && ns.linkProperties != null) {
|
||||||
// Find the interface with the default IPv4 route. It may be the
|
// Find the interface with the default IPv4 route. It may be the
|
||||||
@@ -1790,7 +1790,9 @@ public class Tethering extends BaseNetworkObserver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mLog.log(String.format("OBSERVED LinkProperties update iface=%s state=%s", iface, state));
|
mLog.log(String.format(
|
||||||
|
"OBSERVED LinkProperties update iface=%s state=%s lp=%s",
|
||||||
|
iface, IControlsTethering.getStateString(state), newLp));
|
||||||
final int which = TetherMasterSM.EVENT_IFACE_UPDATE_LINKPROPERTIES;
|
final int which = TetherMasterSM.EVENT_IFACE_UPDATE_LINKPROPERTIES;
|
||||||
mTetherMasterSM.sendMessage(which, state, 0, newLp);
|
mTetherMasterSM.sendMessage(which, state, 0, newLp);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,16 @@ public class IControlsTethering {
|
|||||||
public static final int STATE_TETHERED = 2;
|
public static final int STATE_TETHERED = 2;
|
||||||
public static final int STATE_LOCAL_ONLY = 3;
|
public static final int STATE_LOCAL_ONLY = 3;
|
||||||
|
|
||||||
|
public static String getStateString(int state) {
|
||||||
|
switch (state) {
|
||||||
|
case STATE_UNAVAILABLE: return "UNAVAILABLE";
|
||||||
|
case STATE_AVAILABLE: return "AVAILABLE";
|
||||||
|
case STATE_TETHERED: return "TETHERED";
|
||||||
|
case STATE_LOCAL_ONLY: return "LOCAL_ONLY";
|
||||||
|
}
|
||||||
|
return "UNKNOWN: " + state;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notify that |who| has changed its tethering state.
|
* Notify that |who| has changed its tethering state.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -85,13 +85,16 @@ public class OffloadController {
|
|||||||
mLog.i("tethering offload control not supported");
|
mLog.i("tethering offload control not supported");
|
||||||
stop();
|
stop();
|
||||||
}
|
}
|
||||||
|
mLog.log("tethering offload started");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void stop() {
|
public void stop() {
|
||||||
|
final boolean wasStarted = started();
|
||||||
mUpstreamLinkProperties = null;
|
mUpstreamLinkProperties = null;
|
||||||
mHwInterface.stopOffloadControl();
|
mHwInterface.stopOffloadControl();
|
||||||
mControlInitialized = false;
|
mControlInitialized = false;
|
||||||
mConfigInitialized = false;
|
mConfigInitialized = false;
|
||||||
|
if (wasStarted) mLog.log("tethering offload stopped");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUpstreamLinkProperties(LinkProperties lp) {
|
public void setUpstreamLinkProperties(LinkProperties lp) {
|
||||||
|
|||||||
@@ -56,9 +56,10 @@ import java.util.Objects;
|
|||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @hide
|
* Provides the interface to IP-layer serving functionality for a given network
|
||||||
|
* interface, e.g. for tethering or "local-only hotspot" mode.
|
||||||
*
|
*
|
||||||
* Tracks the eligibility of a given network interface for tethering.
|
* @hide
|
||||||
*/
|
*/
|
||||||
public class TetherInterfaceStateMachine extends StateMachine {
|
public class TetherInterfaceStateMachine extends StateMachine {
|
||||||
private static final IpPrefix LINK_LOCAL_PREFIX = new IpPrefix("fe80::/64");
|
private static final IpPrefix LINK_LOCAL_PREFIX = new IpPrefix("fe80::/64");
|
||||||
@@ -117,6 +118,12 @@ public class TetherInterfaceStateMachine extends StateMachine {
|
|||||||
private String mMyUpstreamIfaceName; // may change over time
|
private String mMyUpstreamIfaceName; // may change over time
|
||||||
private NetworkInterface mNetworkInterface;
|
private NetworkInterface mNetworkInterface;
|
||||||
private byte[] mHwAddr;
|
private byte[] mHwAddr;
|
||||||
|
// TODO: De-duplicate this with mLinkProperties above. Currently, these link
|
||||||
|
// properties are those selected by the IPv6TetheringCoordinator and relayed
|
||||||
|
// to us. By comparison, mLinkProperties contains the addresses and directly
|
||||||
|
// connected routes that have been formed from these properties iff. we have
|
||||||
|
// succeeded in configuring them and are able to announce them within Router
|
||||||
|
// Advertisements (otherwise, we do not add them to mLinkProperties at all).
|
||||||
private LinkProperties mLastIPv6LinkProperties;
|
private LinkProperties mLastIPv6LinkProperties;
|
||||||
private RouterAdvertisementDaemon mRaDaemon;
|
private RouterAdvertisementDaemon mRaDaemon;
|
||||||
private RaParams mLastRaParams;
|
private RaParams mLastRaParams;
|
||||||
@@ -133,7 +140,7 @@ public class TetherInterfaceStateMachine extends StateMachine {
|
|||||||
mIfaceName = ifaceName;
|
mIfaceName = ifaceName;
|
||||||
mInterfaceType = interfaceType;
|
mInterfaceType = interfaceType;
|
||||||
mLinkProperties = new LinkProperties();
|
mLinkProperties = new LinkProperties();
|
||||||
mLinkProperties.setInterfaceName(mIfaceName);
|
resetLinkProperties();
|
||||||
mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
|
mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
|
||||||
|
|
||||||
mInitialState = new InitialState();
|
mInitialState = new InitialState();
|
||||||
@@ -162,10 +169,15 @@ public class TetherInterfaceStateMachine extends StateMachine {
|
|||||||
* Internals.
|
* Internals.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// configured when we start tethering and unconfig'd on error or conclusion
|
private boolean startIPv4() { return configureIPv4(true); }
|
||||||
private boolean configureIfaceIp(boolean enabled) {
|
|
||||||
if (VDBG) Log.d(TAG, "configureIfaceIp(" + enabled + ")");
|
|
||||||
|
|
||||||
|
private void stopIPv4() { configureIPv4(false); }
|
||||||
|
|
||||||
|
private boolean configureIPv4(boolean enabled) {
|
||||||
|
if (VDBG) Log.d(TAG, "configureIPv4(" + enabled + ")");
|
||||||
|
|
||||||
|
// TODO: Replace this hard-coded information with dynamically selected
|
||||||
|
// config passed down to us by a higher layer IP-coordinating element.
|
||||||
String ipAsString = null;
|
String ipAsString = null;
|
||||||
int prefixLen = 0;
|
int prefixLen = 0;
|
||||||
if (mInterfaceType == ConnectivityManager.TETHERING_USB) {
|
if (mInterfaceType == ConnectivityManager.TETHERING_USB) {
|
||||||
@@ -179,15 +191,20 @@ public class TetherInterfaceStateMachine extends StateMachine {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
InterfaceConfiguration ifcg = null;
|
final LinkAddress linkAddr;
|
||||||
try {
|
try {
|
||||||
ifcg = mNMService.getInterfaceConfig(mIfaceName);
|
final InterfaceConfiguration ifcg = mNMService.getInterfaceConfig(mIfaceName);
|
||||||
if (ifcg != null) {
|
if (ifcg == null) {
|
||||||
|
mLog.e("Received null interface config");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
InetAddress addr = NetworkUtils.numericToInetAddress(ipAsString);
|
InetAddress addr = NetworkUtils.numericToInetAddress(ipAsString);
|
||||||
ifcg.setLinkAddress(new LinkAddress(addr, prefixLen));
|
linkAddr = new LinkAddress(addr, prefixLen);
|
||||||
|
ifcg.setLinkAddress(linkAddr);
|
||||||
if (mInterfaceType == ConnectivityManager.TETHERING_WIFI) {
|
if (mInterfaceType == ConnectivityManager.TETHERING_WIFI) {
|
||||||
// The WiFi stack has ownership of the interface up/down state.
|
// The WiFi stack has ownership of the interface up/down state.
|
||||||
// It is unclear whether the bluetooth or USB stacks will manage their own
|
// It is unclear whether the Bluetooth or USB stacks will manage their own
|
||||||
// state.
|
// state.
|
||||||
ifcg.ignoreInterfaceUpDownStatus();
|
ifcg.ignoreInterfaceUpDownStatus();
|
||||||
} else {
|
} else {
|
||||||
@@ -199,12 +216,20 @@ public class TetherInterfaceStateMachine extends StateMachine {
|
|||||||
}
|
}
|
||||||
ifcg.clearFlag("running");
|
ifcg.clearFlag("running");
|
||||||
mNMService.setInterfaceConfig(mIfaceName, ifcg);
|
mNMService.setInterfaceConfig(mIfaceName, ifcg);
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
mLog.e("Error configuring interface " + e);
|
mLog.e("Error configuring interface " + e);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Directly-connected route.
|
||||||
|
final RouteInfo route = new RouteInfo(linkAddr);
|
||||||
|
if (enabled) {
|
||||||
|
mLinkProperties.addLinkAddress(linkAddr);
|
||||||
|
mLinkProperties.addRoute(route);
|
||||||
|
} else {
|
||||||
|
mLinkProperties.removeLinkAddress(linkAddr);
|
||||||
|
mLinkProperties.removeRoute(route);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -294,7 +319,7 @@ public class TetherInterfaceStateMachine extends StateMachine {
|
|||||||
mLastIPv6LinkProperties = v6only;
|
mLastIPv6LinkProperties = v6only;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void configureLocalRoutes(
|
private void configureLocalIPv6Routes(
|
||||||
HashSet<IpPrefix> deprecatedPrefixes, HashSet<IpPrefix> newPrefixes) {
|
HashSet<IpPrefix> deprecatedPrefixes, HashSet<IpPrefix> newPrefixes) {
|
||||||
// [1] Remove the routes that are deprecated.
|
// [1] Remove the routes that are deprecated.
|
||||||
if (!deprecatedPrefixes.isEmpty()) {
|
if (!deprecatedPrefixes.isEmpty()) {
|
||||||
@@ -309,6 +334,8 @@ public class TetherInterfaceStateMachine extends StateMachine {
|
|||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
mLog.e("Failed to remove IPv6 routes from local table: " + e);
|
mLog.e("Failed to remove IPv6 routes from local table: " + e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (RouteInfo route : toBeRemoved) mLinkProperties.removeRoute(route);
|
||||||
}
|
}
|
||||||
|
|
||||||
// [2] Add only the routes that have not previously been added.
|
// [2] Add only the routes that have not previously been added.
|
||||||
@@ -340,11 +367,13 @@ public class TetherInterfaceStateMachine extends StateMachine {
|
|||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
mLog.e("Failed to add IPv6 routes to local table: " + e);
|
mLog.e("Failed to add IPv6 routes to local table: " + e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (RouteInfo route : toBeAdded) mLinkProperties.addRoute(route);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void configureLocalDns(
|
private void configureLocalIPv6Dns(
|
||||||
HashSet<Inet6Address> deprecatedDnses, HashSet<Inet6Address> newDnses) {
|
HashSet<Inet6Address> deprecatedDnses, HashSet<Inet6Address> newDnses) {
|
||||||
final INetd netd = NetdService.getInstance();
|
final INetd netd = NetdService.getInstance();
|
||||||
if (netd == null) {
|
if (netd == null) {
|
||||||
@@ -362,6 +391,8 @@ public class TetherInterfaceStateMachine extends StateMachine {
|
|||||||
} catch (ServiceSpecificException | RemoteException e) {
|
} catch (ServiceSpecificException | RemoteException e) {
|
||||||
mLog.e("Failed to remove local dns IP " + dnsString + ": " + e);
|
mLog.e("Failed to remove local dns IP " + dnsString + ": " + e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mLinkProperties.removeLinkAddress(new LinkAddress(dns, RFC7421_PREFIX_LENGTH));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -380,6 +411,8 @@ public class TetherInterfaceStateMachine extends StateMachine {
|
|||||||
mLog.e("Failed to add local dns IP " + dnsString + ": " + e);
|
mLog.e("Failed to add local dns IP " + dnsString + ": " + e);
|
||||||
newDnses.remove(dns);
|
newDnses.remove(dns);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mLinkProperties.addLinkAddress(new LinkAddress(dns, RFC7421_PREFIX_LENGTH));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -396,10 +429,10 @@ public class TetherInterfaceStateMachine extends StateMachine {
|
|||||||
final RaParams deprecatedParams =
|
final RaParams deprecatedParams =
|
||||||
RaParams.getDeprecatedRaParams(mLastRaParams, newParams);
|
RaParams.getDeprecatedRaParams(mLastRaParams, newParams);
|
||||||
|
|
||||||
configureLocalRoutes(deprecatedParams.prefixes,
|
configureLocalIPv6Routes(deprecatedParams.prefixes,
|
||||||
(newParams != null) ? newParams.prefixes : null);
|
(newParams != null) ? newParams.prefixes : null);
|
||||||
|
|
||||||
configureLocalDns(deprecatedParams.dnses,
|
configureLocalIPv6Dns(deprecatedParams.dnses,
|
||||||
(newParams != null) ? newParams.dnses : null);
|
(newParams != null) ? newParams.dnses : null);
|
||||||
|
|
||||||
mRaDaemon.buildNewRa(deprecatedParams, newParams);
|
mRaDaemon.buildNewRa(deprecatedParams, newParams);
|
||||||
@@ -419,12 +452,19 @@ public class TetherInterfaceStateMachine extends StateMachine {
|
|||||||
private void sendInterfaceState(int newInterfaceState) {
|
private void sendInterfaceState(int newInterfaceState) {
|
||||||
mTetherController.updateInterfaceState(
|
mTetherController.updateInterfaceState(
|
||||||
TetherInterfaceStateMachine.this, newInterfaceState, mLastError);
|
TetherInterfaceStateMachine.this, newInterfaceState, mLastError);
|
||||||
// TODO: Populate mLinkProperties correctly, and send more sensible
|
sendLinkProperties();
|
||||||
// updates more frequently (not just here).
|
}
|
||||||
|
|
||||||
|
private void sendLinkProperties() {
|
||||||
mTetherController.updateLinkProperties(
|
mTetherController.updateLinkProperties(
|
||||||
TetherInterfaceStateMachine.this, new LinkProperties(mLinkProperties));
|
TetherInterfaceStateMachine.this, new LinkProperties(mLinkProperties));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void resetLinkProperties() {
|
||||||
|
mLinkProperties.clear();
|
||||||
|
mLinkProperties.setInterfaceName(mIfaceName);
|
||||||
|
}
|
||||||
|
|
||||||
class InitialState extends State {
|
class InitialState extends State {
|
||||||
@Override
|
@Override
|
||||||
public void enter() {
|
public void enter() {
|
||||||
@@ -464,7 +504,7 @@ public class TetherInterfaceStateMachine extends StateMachine {
|
|||||||
class BaseServingState extends State {
|
class BaseServingState extends State {
|
||||||
@Override
|
@Override
|
||||||
public void enter() {
|
public void enter() {
|
||||||
if (!configureIfaceIp(true)) {
|
if (!startIPv4()) {
|
||||||
mLastError = ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR;
|
mLastError = ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -498,7 +538,9 @@ public class TetherInterfaceStateMachine extends StateMachine {
|
|||||||
mLog.e("Failed to untether interface: " + e);
|
mLog.e("Failed to untether interface: " + e);
|
||||||
}
|
}
|
||||||
|
|
||||||
configureIfaceIp(false);
|
stopIPv4();
|
||||||
|
|
||||||
|
resetLinkProperties();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -515,6 +557,7 @@ public class TetherInterfaceStateMachine extends StateMachine {
|
|||||||
break;
|
break;
|
||||||
case CMD_IPV6_TETHER_UPDATE:
|
case CMD_IPV6_TETHER_UPDATE:
|
||||||
updateUpstreamIPv6LinkProperties((LinkProperties) message.obj);
|
updateUpstreamIPv6LinkProperties((LinkProperties) message.obj);
|
||||||
|
sendLinkProperties();
|
||||||
break;
|
break;
|
||||||
case CMD_IP_FORWARDING_ENABLE_ERROR:
|
case CMD_IP_FORWARDING_ENABLE_ERROR:
|
||||||
case CMD_IP_FORWARDING_DISABLE_ERROR:
|
case CMD_IP_FORWARDING_DISABLE_ERROR:
|
||||||
@@ -625,7 +668,6 @@ public class TetherInterfaceStateMachine extends StateMachine {
|
|||||||
if (super.processMessage(message)) return true;
|
if (super.processMessage(message)) return true;
|
||||||
|
|
||||||
maybeLogMessage(this, message.what);
|
maybeLogMessage(this, message.what);
|
||||||
boolean retValue = true;
|
|
||||||
switch (message.what) {
|
switch (message.what) {
|
||||||
case CMD_TETHER_REQUESTED:
|
case CMD_TETHER_REQUESTED:
|
||||||
mLog.e("CMD_TETHER_REQUESTED while already tethering.");
|
mLog.e("CMD_TETHER_REQUESTED while already tethering.");
|
||||||
@@ -655,10 +697,9 @@ public class TetherInterfaceStateMachine extends StateMachine {
|
|||||||
mMyUpstreamIfaceName = newUpstreamIfaceName;
|
mMyUpstreamIfaceName = newUpstreamIfaceName;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
retValue = false;
|
return false;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
return retValue;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -62,7 +62,8 @@ public class OffloadControllerTest {
|
|||||||
@Mock private OffloadHardwareInterface mHardware;
|
@Mock private OffloadHardwareInterface mHardware;
|
||||||
@Mock private ApplicationInfo mApplicationInfo;
|
@Mock private ApplicationInfo mApplicationInfo;
|
||||||
@Mock private Context mContext;
|
@Mock private Context mContext;
|
||||||
final ArgumentCaptor<ArrayList> mStringArrayCaptor = ArgumentCaptor.forClass(ArrayList.class);
|
private final ArgumentCaptor<ArrayList> mStringArrayCaptor =
|
||||||
|
ArgumentCaptor.forClass(ArrayList.class);
|
||||||
private MockContentResolver mContentResolver;
|
private MockContentResolver mContentResolver;
|
||||||
|
|
||||||
@Before public void setUp() throws Exception {
|
@Before public void setUp() throws Exception {
|
||||||
|
|||||||
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
package com.android.server.connectivity.tethering;
|
package com.android.server.connectivity.tethering;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.mockito.Matchers.any;
|
import static org.mockito.Matchers.any;
|
||||||
import static org.mockito.Matchers.anyString;
|
import static org.mockito.Matchers.anyString;
|
||||||
import static org.mockito.Matchers.eq;
|
import static org.mockito.Matchers.eq;
|
||||||
@@ -40,17 +42,23 @@ import static com.android.server.connectivity.tethering.IControlsTethering.STATE
|
|||||||
import android.net.ConnectivityManager;
|
import android.net.ConnectivityManager;
|
||||||
import android.net.INetworkStatsService;
|
import android.net.INetworkStatsService;
|
||||||
import android.net.InterfaceConfiguration;
|
import android.net.InterfaceConfiguration;
|
||||||
|
import android.net.LinkAddress;
|
||||||
import android.net.LinkProperties;
|
import android.net.LinkProperties;
|
||||||
|
import android.net.RouteInfo;
|
||||||
import android.net.util.SharedLog;
|
import android.net.util.SharedLog;
|
||||||
import android.os.INetworkManagementService;
|
import android.os.INetworkManagementService;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.os.test.TestLooper;
|
import android.os.test.TestLooper;
|
||||||
import android.support.test.filters.SmallTest;
|
import android.support.test.filters.SmallTest;
|
||||||
import android.support.test.runner.AndroidJUnit4;
|
import android.support.test.runner.AndroidJUnit4;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
|
||||||
|
import java.net.Inet4Address;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
import org.mockito.InOrder;
|
import org.mockito.InOrder;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.MockitoAnnotations;
|
import org.mockito.MockitoAnnotations;
|
||||||
@@ -69,6 +77,8 @@ public class TetherInterfaceStateMachineTest {
|
|||||||
@Mock private SharedLog mSharedLog;
|
@Mock private SharedLog mSharedLog;
|
||||||
|
|
||||||
private final TestLooper mLooper = new TestLooper();
|
private final TestLooper mLooper = new TestLooper();
|
||||||
|
private final ArgumentCaptor<LinkProperties> mLinkPropertiesCaptor =
|
||||||
|
ArgumentCaptor.forClass(LinkProperties.class);
|
||||||
private TetherInterfaceStateMachine mTestedSm;
|
private TetherInterfaceStateMachine mTestedSm;
|
||||||
|
|
||||||
private void initStateMachine(int interfaceType) throws Exception {
|
private void initStateMachine(int interfaceType) throws Exception {
|
||||||
@@ -77,7 +87,7 @@ public class TetherInterfaceStateMachineTest {
|
|||||||
mNMService, mStatsService, mTetherHelper);
|
mNMService, mStatsService, mTetherHelper);
|
||||||
mTestedSm.start();
|
mTestedSm.start();
|
||||||
// Starting the state machine always puts us in a consistent state and notifies
|
// Starting the state machine always puts us in a consistent state and notifies
|
||||||
// the test of the world that we've changed from an unknown to available state.
|
// the rest of the world that we've changed from an unknown to available state.
|
||||||
mLooper.dispatchAll();
|
mLooper.dispatchAll();
|
||||||
reset(mNMService, mStatsService, mTetherHelper);
|
reset(mNMService, mStatsService, mTetherHelper);
|
||||||
when(mNMService.getInterfaceConfig(IFACE_NAME)).thenReturn(mInterfaceConfiguration);
|
when(mNMService.getInterfaceConfig(IFACE_NAME)).thenReturn(mInterfaceConfiguration);
|
||||||
@@ -181,7 +191,8 @@ public class TetherInterfaceStateMachineTest {
|
|||||||
inOrder.verify(mTetherHelper).updateInterfaceState(
|
inOrder.verify(mTetherHelper).updateInterfaceState(
|
||||||
mTestedSm, STATE_TETHERED, TETHER_ERROR_NO_ERROR);
|
mTestedSm, STATE_TETHERED, TETHER_ERROR_NO_ERROR);
|
||||||
inOrder.verify(mTetherHelper).updateLinkProperties(
|
inOrder.verify(mTetherHelper).updateLinkProperties(
|
||||||
eq(mTestedSm), any(LinkProperties.class));
|
eq(mTestedSm), mLinkPropertiesCaptor.capture());
|
||||||
|
assertIPv4AddressAndDirectlyConnectedRoute(mLinkPropertiesCaptor.getValue());
|
||||||
verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
|
verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -281,7 +292,8 @@ public class TetherInterfaceStateMachineTest {
|
|||||||
usbTeardownOrder.verify(mTetherHelper).updateInterfaceState(
|
usbTeardownOrder.verify(mTetherHelper).updateInterfaceState(
|
||||||
mTestedSm, STATE_UNAVAILABLE, TETHER_ERROR_NO_ERROR);
|
mTestedSm, STATE_UNAVAILABLE, TETHER_ERROR_NO_ERROR);
|
||||||
usbTeardownOrder.verify(mTetherHelper).updateLinkProperties(
|
usbTeardownOrder.verify(mTetherHelper).updateLinkProperties(
|
||||||
eq(mTestedSm), any(LinkProperties.class));
|
eq(mTestedSm), mLinkPropertiesCaptor.capture());
|
||||||
|
assertNoAddressesNorRoutes(mLinkPropertiesCaptor.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -298,7 +310,8 @@ public class TetherInterfaceStateMachineTest {
|
|||||||
usbTeardownOrder.verify(mTetherHelper).updateInterfaceState(
|
usbTeardownOrder.verify(mTetherHelper).updateInterfaceState(
|
||||||
mTestedSm, STATE_AVAILABLE, TETHER_ERROR_TETHER_IFACE_ERROR);
|
mTestedSm, STATE_AVAILABLE, TETHER_ERROR_TETHER_IFACE_ERROR);
|
||||||
usbTeardownOrder.verify(mTetherHelper).updateLinkProperties(
|
usbTeardownOrder.verify(mTetherHelper).updateLinkProperties(
|
||||||
eq(mTestedSm), any(LinkProperties.class));
|
eq(mTestedSm), mLinkPropertiesCaptor.capture());
|
||||||
|
assertNoAddressesNorRoutes(mLinkPropertiesCaptor.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -313,7 +326,8 @@ public class TetherInterfaceStateMachineTest {
|
|||||||
usbTeardownOrder.verify(mTetherHelper).updateInterfaceState(
|
usbTeardownOrder.verify(mTetherHelper).updateInterfaceState(
|
||||||
mTestedSm, STATE_AVAILABLE, TETHER_ERROR_ENABLE_NAT_ERROR);
|
mTestedSm, STATE_AVAILABLE, TETHER_ERROR_ENABLE_NAT_ERROR);
|
||||||
usbTeardownOrder.verify(mTetherHelper).updateLinkProperties(
|
usbTeardownOrder.verify(mTetherHelper).updateLinkProperties(
|
||||||
eq(mTestedSm), any(LinkProperties.class));
|
eq(mTestedSm), mLinkPropertiesCaptor.capture());
|
||||||
|
assertNoAddressesNorRoutes(mLinkPropertiesCaptor.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -360,4 +374,28 @@ public class TetherInterfaceStateMachineTest {
|
|||||||
upstreamIface);
|
upstreamIface);
|
||||||
mLooper.dispatchAll();
|
mLooper.dispatchAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void assertIPv4AddressAndDirectlyConnectedRoute(LinkProperties lp) {
|
||||||
|
// Find the first IPv4 LinkAddress.
|
||||||
|
LinkAddress addr4 = null;
|
||||||
|
for (LinkAddress addr : lp.getLinkAddresses()) {
|
||||||
|
if (!(addr.getAddress() instanceof Inet4Address)) continue;
|
||||||
|
addr4 = addr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
assertTrue("missing IPv4 address", addr4 != null);
|
||||||
|
|
||||||
|
// Assert the presence of the associated directly connected route.
|
||||||
|
final RouteInfo directlyConnected = new RouteInfo(addr4, null, lp.getInterfaceName());
|
||||||
|
assertTrue("missing directly connected route: '" + directlyConnected.toString() + "'",
|
||||||
|
lp.getRoutes().contains(directlyConnected));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertNoAddressesNorRoutes(LinkProperties lp) {
|
||||||
|
assertTrue(lp.getLinkAddresses().isEmpty());
|
||||||
|
assertTrue(lp.getRoutes().isEmpty());
|
||||||
|
// We also check that interface name is non-empty, because we should
|
||||||
|
// never see an empty interface name in any LinkProperties update.
|
||||||
|
assertFalse(TextUtils.isEmpty(lp.getInterfaceName()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user