Merge changes I8e806b3b,I5e8e4673,Id2a078da

* changes:
  Add CTS tests for EthernetNetworkProvider changes
  Move EthernetNetworkFactory to using the NetworkProvider API
  Improve waiting for interface added or removed
This commit is contained in:
Patrick Rohr
2022-05-24 03:34:25 +00:00
committed by Gerrit Code Review
3 changed files with 217 additions and 181 deletions

View File

@@ -31,10 +31,9 @@ import android.net.IpConfiguration.ProxySettings;
import android.net.LinkProperties; import android.net.LinkProperties;
import android.net.NetworkAgentConfig; import android.net.NetworkAgentConfig;
import android.net.NetworkCapabilities; import android.net.NetworkCapabilities;
import android.net.NetworkFactory;
import android.net.NetworkProvider; import android.net.NetworkProvider;
import android.net.NetworkRequest; import android.net.NetworkRequest;
import android.net.NetworkSpecifier; import android.net.NetworkScore;
import android.net.ip.IIpClient; import android.net.ip.IIpClient;
import android.net.ip.IpClientCallbacks; import android.net.ip.IpClientCallbacks;
import android.net.ip.IpClientManager; import android.net.ip.IpClientManager;
@@ -61,22 +60,19 @@ import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
/** /**
* {@link NetworkFactory} that represents Ethernet networks. * {@link NetworkProvider} that manages NetworkOffers for Ethernet networks.
*
* This class reports a static network score of 70 when it is tracking an interface and that
* interface's link is up, and a score of 0 otherwise.
*/ */
public class EthernetNetworkFactory extends NetworkFactory { public class EthernetNetworkFactory {
private final static String TAG = EthernetNetworkFactory.class.getSimpleName(); private final static String TAG = EthernetNetworkFactory.class.getSimpleName();
final static boolean DBG = true; final static boolean DBG = true;
private final static int NETWORK_SCORE = 70;
private static final String NETWORK_TYPE = "Ethernet"; private static final String NETWORK_TYPE = "Ethernet";
private final ConcurrentHashMap<String, NetworkInterfaceState> mTrackingInterfaces = private final ConcurrentHashMap<String, NetworkInterfaceState> mTrackingInterfaces =
new ConcurrentHashMap<>(); new ConcurrentHashMap<>();
private final Handler mHandler; private final Handler mHandler;
private final Context mContext; private final Context mContext;
private final NetworkProvider mProvider;
final Dependencies mDeps; final Dependencies mDeps;
public static class Dependencies { public static class Dependencies {
@@ -111,54 +107,24 @@ public class EthernetNetworkFactory extends NetworkFactory {
} }
public EthernetNetworkFactory(Handler handler, Context context) { public EthernetNetworkFactory(Handler handler, Context context) {
this(handler, context, new Dependencies()); this(handler, context, new NetworkProvider(context, handler.getLooper(), TAG),
new Dependencies());
} }
@VisibleForTesting @VisibleForTesting
EthernetNetworkFactory(Handler handler, Context context, Dependencies deps) { EthernetNetworkFactory(Handler handler, Context context, NetworkProvider provider,
super(handler.getLooper(), context, NETWORK_TYPE, createDefaultNetworkCapabilities()); Dependencies deps) {
mHandler = handler; mHandler = handler;
mContext = context; mContext = context;
mProvider = provider;
mDeps = deps; mDeps = deps;
setScoreFilter(NETWORK_SCORE);
} }
@Override /**
public boolean acceptRequest(NetworkRequest request) { * Registers the network provider with the system.
if (DBG) { */
Log.d(TAG, "acceptRequest, request: " + request); public void register() {
} mContext.getSystemService(ConnectivityManager.class).registerNetworkProvider(mProvider);
return networkForRequest(request) != null;
}
@Override
protected void needNetworkFor(NetworkRequest networkRequest) {
NetworkInterfaceState network = networkForRequest(networkRequest);
if (network == null) {
Log.e(TAG, "needNetworkFor, failed to get a network for " + networkRequest);
return;
}
if (++network.refCount == 1) {
network.start();
}
}
@Override
protected void releaseNetworkFor(NetworkRequest networkRequest) {
NetworkInterfaceState network = networkForRequest(networkRequest);
if (network == null) {
Log.e(TAG, "releaseNetworkFor, failed to get a network for " + networkRequest);
return;
}
if (--network.refCount == 0) {
network.stop();
}
} }
/** /**
@@ -196,9 +162,8 @@ public class EthernetNetworkFactory extends NetworkFactory {
} }
final NetworkInterfaceState iface = new NetworkInterfaceState( final NetworkInterfaceState iface = new NetworkInterfaceState(
ifaceName, hwAddress, mHandler, mContext, ipConfig, nc, getProvider(), mDeps); ifaceName, hwAddress, mHandler, mContext, ipConfig, nc, mProvider, mDeps);
mTrackingInterfaces.put(ifaceName, iface); mTrackingInterfaces.put(ifaceName, iface);
updateCapabilityFilter();
} }
@VisibleForTesting @VisibleForTesting
@@ -239,7 +204,6 @@ public class EthernetNetworkFactory extends NetworkFactory {
final NetworkInterfaceState iface = mTrackingInterfaces.get(ifaceName); final NetworkInterfaceState iface = mTrackingInterfaces.get(ifaceName);
iface.updateInterface(ipConfig, capabilities, listener); iface.updateInterface(ipConfig, capabilities, listener);
mTrackingInterfaces.put(ifaceName, iface); mTrackingInterfaces.put(ifaceName, iface);
updateCapabilityFilter();
} }
private static NetworkCapabilities mixInCapabilities(NetworkCapabilities nc, private static NetworkCapabilities mixInCapabilities(NetworkCapabilities nc,
@@ -250,16 +214,6 @@ public class EthernetNetworkFactory extends NetworkFactory {
return builder.build(); return builder.build();
} }
private void updateCapabilityFilter() {
NetworkCapabilities capabilitiesFilter = createDefaultNetworkCapabilities();
for (NetworkInterfaceState iface: mTrackingInterfaces.values()) {
capabilitiesFilter = mixInCapabilities(capabilitiesFilter, iface.mCapabilities);
}
if (DBG) Log.d(TAG, "updateCapabilityFilter: " + capabilitiesFilter);
setCapabilityFilter(capabilitiesFilter);
}
private static NetworkCapabilities createDefaultNetworkCapabilities() { private static NetworkCapabilities createDefaultNetworkCapabilities() {
return NetworkCapabilities.Builder return NetworkCapabilities.Builder
.withoutDefaultCapabilities() .withoutDefaultCapabilities()
@@ -270,11 +224,8 @@ public class EthernetNetworkFactory extends NetworkFactory {
protected void removeInterface(String interfaceName) { protected void removeInterface(String interfaceName) {
NetworkInterfaceState iface = mTrackingInterfaces.remove(interfaceName); NetworkInterfaceState iface = mTrackingInterfaces.remove(interfaceName);
if (iface != null) { if (iface != null) {
iface.maybeSendNetworkManagementCallbackForAbort(); iface.destroy();
iface.stop();
} }
updateCapabilityFilter();
} }
/** Returns true if state has been modified */ /** Returns true if state has been modified */
@@ -306,37 +257,6 @@ public class EthernetNetworkFactory extends NetworkFactory {
return mTrackingInterfaces.containsKey(ifaceName); return mTrackingInterfaces.containsKey(ifaceName);
} }
private NetworkInterfaceState networkForRequest(NetworkRequest request) {
String requestedIface = null;
NetworkSpecifier specifier = request.getNetworkSpecifier();
if (specifier instanceof EthernetNetworkSpecifier) {
requestedIface = ((EthernetNetworkSpecifier) specifier)
.getInterfaceName();
}
NetworkInterfaceState network = null;
if (!TextUtils.isEmpty(requestedIface)) {
NetworkInterfaceState n = mTrackingInterfaces.get(requestedIface);
if (n != null && request.canBeSatisfiedBy(n.mCapabilities)) {
network = n;
}
} else {
for (NetworkInterfaceState n : mTrackingInterfaces.values()) {
if (request.canBeSatisfiedBy(n.mCapabilities) && n.mLinkUp) {
network = n;
break;
}
}
}
if (DBG) {
Log.i(TAG, "networkForRequest, request: " + request + ", network: " + network);
}
return network;
}
private static void maybeSendNetworkManagementCallback( private static void maybeSendNetworkManagementCallback(
@Nullable final INetworkInterfaceOutcomeReceiver listener, @Nullable final INetworkInterfaceOutcomeReceiver listener,
@Nullable final String iface, @Nullable final String iface,
@@ -401,8 +321,6 @@ public class EthernetNetworkFactory extends NetworkFactory {
ConnectivityManager.TYPE_NONE); ConnectivityManager.TYPE_NONE);
} }
long refCount = 0;
private class EthernetIpClientCallback extends IpClientCallbacks { private class EthernetIpClientCallback extends IpClientCallbacks {
private final ConditionVariable mIpClientStartCv = new ConditionVariable(false); private final ConditionVariable mIpClientStartCv = new ConditionVariable(false);
private final ConditionVariable mIpClientShutdownCv = new ConditionVariable(false); private final ConditionVariable mIpClientShutdownCv = new ConditionVariable(false);
@@ -476,6 +394,9 @@ public class EthernetNetworkFactory extends NetworkFactory {
private class EthernetNetworkOfferCallback implements NetworkProvider.NetworkOfferCallback { private class EthernetNetworkOfferCallback implements NetworkProvider.NetworkOfferCallback {
@Override @Override
public void onNetworkNeeded(@NonNull NetworkRequest request) { public void onNetworkNeeded(@NonNull NetworkRequest request) {
if (DBG) {
Log.d(TAG, String.format("%s: onNetworkNeeded for request: %s", name, request));
}
// When the network offer is first registered, onNetworkNeeded is called with all // When the network offer is first registered, onNetworkNeeded is called with all
// existing requests. // existing requests.
// ConnectivityService filters requests for us based on the NetworkCapabilities // ConnectivityService filters requests for us based on the NetworkCapabilities
@@ -487,6 +408,10 @@ public class EthernetNetworkFactory extends NetworkFactory {
@Override @Override
public void onNetworkUnneeded(@NonNull NetworkRequest request) { public void onNetworkUnneeded(@NonNull NetworkRequest request) {
if (DBG) {
Log.d(TAG,
String.format("%s: onNetworkUnneeded for request: %s", name, request));
}
mRequests.remove(request); mRequests.remove(request);
if (mRequests.isEmpty()) { if (mRequests.isEmpty()) {
// not currently serving any requests, stop the network. // not currently serving any requests, stop the network.
@@ -529,9 +454,21 @@ public class EthernetNetworkFactory extends NetworkFactory {
+ "transport type."); + "transport type.");
} }
private static NetworkScore getBestNetworkScore() {
return new NetworkScore.Builder().build();
}
private void setCapabilities(@NonNull final NetworkCapabilities capabilities) { private void setCapabilities(@NonNull final NetworkCapabilities capabilities) {
mCapabilities = new NetworkCapabilities(capabilities); mCapabilities = new NetworkCapabilities(capabilities);
mLegacyType = getLegacyType(mCapabilities); mLegacyType = getLegacyType(mCapabilities);
if (mLinkUp) {
// registering a new network offer will update the existing one, not install a
// new one.
mNetworkProvider.registerNetworkOffer(getBestNetworkScore(),
new NetworkCapabilities(capabilities), cmd -> mHandler.post(cmd),
mNetworkOfferCallback);
}
} }
void updateInterface(@Nullable final IpConfiguration ipConfig, void updateInterface(@Nullable final IpConfiguration ipConfig,
@@ -693,20 +630,21 @@ public class EthernetNetworkFactory extends NetworkFactory {
mLinkUp = up; mLinkUp = up;
if (!up) { // was up, goes down if (!up) { // was up, goes down
// Send an abort on a provisioning request callback if necessary before stopping. // retract network offer and stop IpClient.
maybeSendNetworkManagementCallbackForAbort(); destroy();
stop();
// If only setting the interface down, send a callback to signal completion. // If only setting the interface down, send a callback to signal completion.
EthernetNetworkFactory.maybeSendNetworkManagementCallback(listener, name, null); EthernetNetworkFactory.maybeSendNetworkManagementCallback(listener, name, null);
} else { // was down, goes up } else { // was down, goes up
stop(); // register network offer
start(listener); mNetworkProvider.registerNetworkOffer(getBestNetworkScore(),
new NetworkCapabilities(mCapabilities), (cmd) -> mHandler.post(cmd),
mNetworkOfferCallback);
} }
return true; return true;
} }
void stop() { private void stop() {
// Invalidate all previous start requests // Invalidate all previous start requests
if (mIpClient != null) { if (mIpClient != null) {
mIpClient.shutdown(); mIpClient.shutdown();
@@ -722,6 +660,13 @@ public class EthernetNetworkFactory extends NetworkFactory {
mLinkProperties.clear(); mLinkProperties.clear();
} }
public void destroy() {
mNetworkProvider.unregisterNetworkOffer(mNetworkOfferCallback);
maybeSendNetworkManagementCallbackForAbort();
stop();
mRequests.clear();
}
private static void provisionIpClient(@NonNull final IpClientManager ipClient, private static void provisionIpClient(@NonNull final IpClientManager ipClient,
@NonNull final IpConfiguration config, @NonNull final String tcpBufferSizes) { @NonNull final IpConfiguration config, @NonNull final String tcpBufferSizes) {
if (config.getProxySettings() == ProxySettings.STATIC || if (config.getProxySettings() == ProxySettings.STATIC ||
@@ -761,7 +706,6 @@ public class EthernetNetworkFactory extends NetworkFactory {
@Override @Override
public String toString() { public String toString() {
return getClass().getSimpleName() + "{ " return getClass().getSimpleName() + "{ "
+ "refCount: " + refCount + ", "
+ "iface: " + name + ", " + "iface: " + name + ", "
+ "up: " + mLinkUp + ", " + "up: " + mLinkUp + ", "
+ "hwAddress: " + mHwAddress + ", " + "hwAddress: " + mHwAddress + ", "
@@ -774,7 +718,6 @@ public class EthernetNetworkFactory extends NetworkFactory {
} }
void dump(FileDescriptor fd, IndentingPrintWriter pw, String[] args) { void dump(FileDescriptor fd, IndentingPrintWriter pw, String[] args) {
super.dump(fd, pw, args);
pw.println(getClass().getSimpleName()); pw.println(getClass().getSimpleName());
pw.println("Tracking interfaces:"); pw.println("Tracking interfaces:");
pw.increaseIndent(); pw.increaseIndent();

View File

@@ -19,9 +19,16 @@ import android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS
import android.Manifest.permission.MANAGE_TEST_NETWORKS import android.Manifest.permission.MANAGE_TEST_NETWORKS
import android.Manifest.permission.NETWORK_SETTINGS import android.Manifest.permission.NETWORK_SETTINGS
import android.content.Context import android.content.Context
import android.net.ConnectivityManager
import android.net.EthernetNetworkSpecifier
import android.net.InetAddresses import android.net.InetAddresses
import android.net.IpConfiguration import android.net.IpConfiguration
import android.net.MacAddress import android.net.MacAddress
import android.net.Network
import android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED
import android.net.NetworkCapabilities.TRANSPORT_ETHERNET
import android.net.NetworkCapabilities.TRANSPORT_TEST
import android.net.NetworkRequest
import android.net.TestNetworkInterface import android.net.TestNetworkInterface
import android.net.TestNetworkManager import android.net.TestNetworkManager
import android.net.cts.EthernetManagerTest.EthernetStateListener.CallbackEntry.InterfaceStateChanged import android.net.cts.EthernetManagerTest.EthernetStateListener.CallbackEntry.InterfaceStateChanged
@@ -41,10 +48,14 @@ import com.android.networkstack.apishim.common.EthernetManagerShim.ROLE_NONE
import com.android.networkstack.apishim.common.EthernetManagerShim.STATE_ABSENT import com.android.networkstack.apishim.common.EthernetManagerShim.STATE_ABSENT
import com.android.networkstack.apishim.common.EthernetManagerShim.STATE_LINK_DOWN import com.android.networkstack.apishim.common.EthernetManagerShim.STATE_LINK_DOWN
import com.android.networkstack.apishim.common.EthernetManagerShim.STATE_LINK_UP import com.android.networkstack.apishim.common.EthernetManagerShim.STATE_LINK_UP
import com.android.testutils.anyNetwork
import com.android.testutils.DevSdkIgnoreRule import com.android.testutils.DevSdkIgnoreRule
import com.android.testutils.RecorderCallback.CallbackEntry.Available
import com.android.testutils.RecorderCallback.CallbackEntry.Lost
import com.android.testutils.RouterAdvertisementResponder import com.android.testutils.RouterAdvertisementResponder
import com.android.testutils.SC_V2 import com.android.testutils.SC_V2
import com.android.testutils.TapPacketReader import com.android.testutils.TapPacketReader
import com.android.testutils.TestableNetworkCallback
import com.android.testutils.runAsShell import com.android.testutils.runAsShell
import com.android.testutils.waitForIdle import com.android.testutils.waitForIdle
import org.junit.After import org.junit.After
@@ -64,6 +75,11 @@ private const val TIMEOUT_MS = 1000L
private const val NO_CALLBACK_TIMEOUT_MS = 200L private const val NO_CALLBACK_TIMEOUT_MS = 200L
private val DEFAULT_IP_CONFIGURATION = IpConfiguration(IpConfiguration.IpAssignment.DHCP, private val DEFAULT_IP_CONFIGURATION = IpConfiguration(IpConfiguration.IpAssignment.DHCP,
IpConfiguration.ProxySettings.NONE, null, null) IpConfiguration.ProxySettings.NONE, null, null)
private val ETH_REQUEST: NetworkRequest = NetworkRequest.Builder()
.addTransportType(TRANSPORT_TEST)
.addTransportType(TRANSPORT_ETHERNET)
.removeCapability(NET_CAPABILITY_TRUSTED)
.build()
@AppModeFull(reason = "Instant apps can't access EthernetManager") @AppModeFull(reason = "Instant apps can't access EthernetManager")
@RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class)
@@ -74,10 +90,12 @@ class EthernetManagerTest {
private val context by lazy { InstrumentationRegistry.getInstrumentation().context } private val context by lazy { InstrumentationRegistry.getInstrumentation().context }
private val em by lazy { EthernetManagerShimImpl.newInstance(context) } private val em by lazy { EthernetManagerShimImpl.newInstance(context) }
private val cm by lazy { context.getSystemService(ConnectivityManager::class.java) }
private val ifaceListener = EthernetStateListener() private val ifaceListener = EthernetStateListener()
private val createdIfaces = ArrayList<EthernetTestInterface>() private val createdIfaces = ArrayList<EthernetTestInterface>()
private val addedListeners = ArrayList<EthernetStateListener>() private val addedListeners = ArrayList<EthernetStateListener>()
private val networkRequests = ArrayList<TestableNetworkCallback>()
private class EthernetTestInterface( private class EthernetTestInterface(
context: Context, context: Context,
@@ -177,10 +195,12 @@ class EthernetManagerTest {
setIncludeTestInterfaces(false) setIncludeTestInterfaces(false)
for (iface in createdIfaces) { for (iface in createdIfaces) {
iface.destroy() iface.destroy()
ifaceListener.eventuallyExpect(iface, STATE_ABSENT, ROLE_NONE)
} }
for (listener in addedListeners) { for (listener in addedListeners) {
em.removeInterfaceStateListener(listener) em.removeInterfaceStateListener(listener)
} }
networkRequests.forEach { cm.unregisterNetworkCallback(it) }
} }
private fun addInterfaceStateListener(listener: EthernetStateListener) { private fun addInterfaceStateListener(listener: EthernetStateListener) {
@@ -195,7 +215,11 @@ class EthernetManagerTest {
context, context,
Handler(Looper.getMainLooper()) Handler(Looper.getMainLooper())
).also { createdIfaces.add(it) } ).also { createdIfaces.add(it) }
ifaceListener.eventuallyExpect(iface, STATE_LINK_UP, ROLE_CLIENT) with(ifaceListener) {
// when an interface comes up, we should always see a down cb before an up cb.
eventuallyExpect(iface, STATE_LINK_DOWN, ROLE_CLIENT)
expectCallback(iface, STATE_LINK_UP, ROLE_CLIENT)
}
return iface return iface
} }
@@ -208,8 +232,37 @@ class EthernetManagerTest {
private fun removeInterface(iface: EthernetTestInterface) { private fun removeInterface(iface: EthernetTestInterface) {
iface.destroy() iface.destroy()
createdIfaces.remove(iface) createdIfaces.remove(iface)
ifaceListener.eventuallyExpect(iface, STATE_ABSENT, ROLE_NONE)
} }
private fun requestNetwork(request: NetworkRequest): TestableNetworkCallback {
return TestableNetworkCallback().also {
cm.requestNetwork(request, it)
networkRequests.add(it)
}
}
private fun releaseNetwork(cb: TestableNetworkCallback) {
cm.unregisterNetworkCallback(cb)
networkRequests.remove(cb)
}
private fun NetworkRequest.createCopyWithEthernetSpecifier(ifaceName: String) =
NetworkRequest.Builder(NetworkRequest(ETH_REQUEST))
.setNetworkSpecifier(EthernetNetworkSpecifier(ifaceName)).build()
// It can take multiple seconds for the network to become available.
private fun TestableNetworkCallback.expectAvailable() =
expectCallback<Available>(anyNetwork(), 5000/*ms timeout*/).network
// b/233534110: eventuallyExpect<Lost>() does not advance ReadHead, use
// eventuallyExpect(Lost::class) instead.
private fun TestableNetworkCallback.eventuallyExpectLost(n: Network? = null) =
eventuallyExpect(Lost::class, TIMEOUT_MS) { n?.equals(it.network) ?: true }
private fun TestableNetworkCallback.assertNotLost(n: Network? = null) =
assertNoCallbackThat() { it is Lost && (n?.equals(it.network) ?: true) }
@Test @Test
fun testCallbacks() { fun testCallbacks() {
// If an interface exists when the callback is registered, it is reported on registration. // If an interface exists when the callback is registered, it is reported on registration.
@@ -289,4 +342,105 @@ class EthernetManagerTest {
removeInterface(iface2) removeInterface(iface2)
} }
@Test
fun testNetworkRequest_withSingleExistingInterface() {
setIncludeTestInterfaces(true)
createInterface()
// install a listener which will later be used to verify the Lost callback
val listenerCb = TestableNetworkCallback()
cm.registerNetworkCallback(ETH_REQUEST, listenerCb)
networkRequests.add(listenerCb)
val cb = requestNetwork(ETH_REQUEST)
val network = cb.expectAvailable()
cb.assertNotLost()
releaseNetwork(cb)
listenerCb.eventuallyExpectLost(network)
}
@Test
fun testNetworkRequest_beforeSingleInterfaceIsUp() {
setIncludeTestInterfaces(true)
val cb = requestNetwork(ETH_REQUEST)
// bring up interface after network has been requested
val iface = createInterface()
val network = cb.expectAvailable()
// remove interface before network request has been removed
cb.assertNotLost()
removeInterface(iface)
cb.eventuallyExpectLost()
releaseNetwork(cb)
}
@Test
fun testNetworkRequest_withMultipleInterfaces() {
setIncludeTestInterfaces(true)
val iface1 = createInterface()
val iface2 = createInterface()
val cb = requestNetwork(ETH_REQUEST.createCopyWithEthernetSpecifier(iface2.interfaceName))
val network = cb.expectAvailable()
cb.expectCapabilitiesThat(network) {
it.networkSpecifier == EthernetNetworkSpecifier(iface2.interfaceName)
}
removeInterface(iface1)
cb.assertNotLost()
removeInterface(iface2)
cb.eventuallyExpectLost()
releaseNetwork(cb)
}
@Test
fun testNetworkRequest_withInterfaceBeingReplaced() {
setIncludeTestInterfaces(true)
val iface1 = createInterface()
val cb = requestNetwork(ETH_REQUEST)
val network = cb.expectAvailable()
// create another network and verify the request sticks to the current network
val iface2 = createInterface()
cb.assertNotLost()
// remove iface1 and verify the request brings up iface2
removeInterface(iface1)
cb.eventuallyExpectLost(network)
val network2 = cb.expectAvailable()
releaseNetwork(cb)
}
@Test
fun testNetworkRequest_withMultipleInterfacesAndRequests() {
setIncludeTestInterfaces(true)
val iface1 = createInterface()
val iface2 = createInterface()
val cb1 = requestNetwork(ETH_REQUEST.createCopyWithEthernetSpecifier(iface1.interfaceName))
val cb2 = requestNetwork(ETH_REQUEST.createCopyWithEthernetSpecifier(iface2.interfaceName))
val cb3 = requestNetwork(ETH_REQUEST)
cb1.expectAvailable()
cb2.expectAvailable()
cb3.expectAvailable()
cb1.assertNotLost()
cb2.assertNotLost()
cb3.assertNotLost()
releaseNetwork(cb1)
releaseNetwork(cb2)
releaseNetwork(cb3)
}
} }

View File

@@ -32,7 +32,6 @@ import static org.mockito.ArgumentMatchers.same;
import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@@ -51,6 +50,7 @@ import android.net.Network;
import android.net.NetworkAgentConfig; import android.net.NetworkAgentConfig;
import android.net.NetworkCapabilities; import android.net.NetworkCapabilities;
import android.net.NetworkProvider; import android.net.NetworkProvider;
import android.net.NetworkProvider.NetworkOfferCallback;
import android.net.NetworkRequest; import android.net.NetworkRequest;
import android.net.StaticIpConfiguration; import android.net.StaticIpConfiguration;
import android.net.ip.IpClientCallbacks; import android.net.ip.IpClientCallbacks;
@@ -99,6 +99,7 @@ public class EthernetNetworkFactoryTest {
@Mock private EthernetNetworkAgent mNetworkAgent; @Mock private EthernetNetworkAgent mNetworkAgent;
@Mock private InterfaceParams mInterfaceParams; @Mock private InterfaceParams mInterfaceParams;
@Mock private Network mMockNetwork; @Mock private Network mMockNetwork;
@Mock private NetworkProvider mNetworkProvider;
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
@@ -112,7 +113,7 @@ public class EthernetNetworkFactoryTest {
private void initEthernetNetworkFactory() { private void initEthernetNetworkFactory() {
mLooper = new TestLooper(); mLooper = new TestLooper();
mHandler = new Handler(mLooper.getLooper()); mHandler = new Handler(mLooper.getLooper());
mNetFactory = new EthernetNetworkFactory(mHandler, mContext, mDeps); mNetFactory = new EthernetNetworkFactory(mHandler, mContext, mNetworkProvider, mDeps);
} }
private void setupNetworkAgentMock() { private void setupNetworkAgentMock() {
@@ -239,9 +240,16 @@ public class EthernetNetworkFactoryTest {
mNetFactory.addInterface(iface, HW_ADDR, ipConfig, mNetFactory.addInterface(iface, HW_ADDR, ipConfig,
createInterfaceCapsBuilder(transportType).build()); createInterfaceCapsBuilder(transportType).build());
assertTrue(mNetFactory.updateInterfaceLinkState(iface, true, NULL_LISTENER)); assertTrue(mNetFactory.updateInterfaceLinkState(iface, true, NULL_LISTENER));
ArgumentCaptor<NetworkOfferCallback> captor = ArgumentCaptor.forClass(
NetworkOfferCallback.class);
verify(mNetworkProvider).registerNetworkOffer(any(), any(), any(), captor.capture());
captor.getValue().onNetworkNeeded(createDefaultRequest());
verifyStart(ipConfig); verifyStart(ipConfig);
clearInvocations(mDeps); clearInvocations(mDeps);
clearInvocations(mIpClient); clearInvocations(mIpClient);
clearInvocations(mNetworkProvider);
} }
// creates a provisioned interface // creates a provisioned interface
@@ -281,28 +289,14 @@ public class EthernetNetworkFactoryTest {
// To create an unprovisioned interface, provision and then "stop" it, i.e. stop its // To create an unprovisioned interface, provision and then "stop" it, i.e. stop its
// NetworkAgent and IpClient. One way this can be done is by provisioning an interface and // NetworkAgent and IpClient. One way this can be done is by provisioning an interface and
// then calling onNetworkUnwanted. // then calling onNetworkUnwanted.
createAndVerifyProvisionedInterface(iface); mNetFactory.addInterface(iface, HW_ADDR, createDefaultIpConfig(),
createInterfaceCapsBuilder(NetworkCapabilities.TRANSPORT_ETHERNET).build());
mNetworkAgent.getCallbacks().onNetworkUnwanted(); assertTrue(mNetFactory.updateInterfaceLinkState(iface, true, NULL_LISTENER));
mLooper.dispatchAll();
verifyStop();
clearInvocations(mIpClient); clearInvocations(mIpClient);
clearInvocations(mNetworkAgent); clearInvocations(mNetworkAgent);
} }
@Test
public void testAcceptRequest() throws Exception {
initEthernetNetworkFactory();
createInterfaceUndergoingProvisioning(TEST_IFACE);
assertTrue(mNetFactory.acceptRequest(createDefaultRequest()));
NetworkRequest wifiRequest = createDefaultRequestBuilder()
.removeTransportType(NetworkCapabilities.TRANSPORT_ETHERNET)
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI).build();
assertFalse(mNetFactory.acceptRequest(wifiRequest));
}
@Test @Test
public void testUpdateInterfaceLinkStateForActiveProvisioningInterface() throws Exception { public void testUpdateInterfaceLinkStateForActiveProvisioningInterface() throws Exception {
initEthernetNetworkFactory(); initEthernetNetworkFactory();
@@ -377,36 +371,6 @@ public class EthernetNetworkFactoryTest {
listener.expectOnError(); listener.expectOnError();
} }
@Test
public void testNeedNetworkForOnProvisionedInterface() throws Exception {
initEthernetNetworkFactory();
createAndVerifyProvisionedInterface(TEST_IFACE);
mNetFactory.needNetworkFor(createDefaultRequest());
verify(mIpClient, never()).startProvisioning(any());
}
@Test
public void testNeedNetworkForOnUnprovisionedInterface() throws Exception {
initEthernetNetworkFactory();
createUnprovisionedInterface(TEST_IFACE);
mNetFactory.needNetworkFor(createDefaultRequest());
verify(mIpClient).startProvisioning(any());
triggerOnProvisioningSuccess();
verifyNetworkAgentRegistersAndConnects();
}
@Test
public void testNeedNetworkForOnInterfaceUndergoingProvisioning() throws Exception {
initEthernetNetworkFactory();
createInterfaceUndergoingProvisioning(TEST_IFACE);
mNetFactory.needNetworkFor(createDefaultRequest());
verify(mIpClient, never()).startProvisioning(any());
triggerOnProvisioningSuccess();
verifyNetworkAgentRegistersAndConnects();
}
@Test @Test
public void testProvisioningLoss() throws Exception { public void testProvisioningLoss() throws Exception {
initEthernetNetworkFactory(); initEthernetNetworkFactory();
@@ -440,31 +404,6 @@ public class EthernetNetworkFactoryTest {
verify(mIpClient, never()).startProvisioning(any()); verify(mIpClient, never()).startProvisioning(any());
} }
@Test
public void testIpClientIsNotStartedWhenLinkIsDown() throws Exception {
initEthernetNetworkFactory();
createUnprovisionedInterface(TEST_IFACE);
mNetFactory.updateInterfaceLinkState(TEST_IFACE, false, NULL_LISTENER);
mNetFactory.needNetworkFor(createDefaultRequest());
verify(mDeps, never()).makeIpClient(any(), any(), any());
// BUG(b/191854824): requesting a network with a specifier (Android Auto use case) should
// not start an IpClient when the link is down, but fixing this may make matters worse by
// tiggering b/197548738.
NetworkRequest specificNetRequest = new NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET)
.setNetworkSpecifier(new EthernetNetworkSpecifier(TEST_IFACE))
.build();
mNetFactory.needNetworkFor(specificNetRequest);
mNetFactory.releaseNetworkFor(specificNetRequest);
mNetFactory.updateInterfaceLinkState(TEST_IFACE, true, NULL_LISTENER);
// TODO: change to once when b/191854824 is fixed.
verify(mDeps, times(2)).makeIpClient(any(), eq(TEST_IFACE), any());
}
@Test @Test
public void testLinkPropertiesChanged() throws Exception { public void testLinkPropertiesChanged() throws Exception {
initEthernetNetworkFactory(); initEthernetNetworkFactory();