Merge changes I7ad55374,I4a0c7f6e into main
* changes:
Add test to verify callbacks for enable/disableInterface APIs
Fix enable/disableInterface APIs to properly affect administrative state
diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java
index 8fb632e..bfcc171 100644
--- a/service-t/src/com/android/server/ethernet/EthernetTracker.java
+++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java
@@ -384,7 +384,7 @@
/** Configure the administrative state of ethernet interface by toggling IFF_UP. */
public void setInterfaceEnabled(String iface, boolean enabled, EthernetCallback cb) {
- mHandler.post(() -> updateInterfaceState(iface, enabled, cb));
+ mHandler.post(() -> setInterfaceAdministrativeState(iface, enabled, cb));
}
IpConfiguration getIpConfiguration(String iface) {
@@ -642,25 +642,40 @@
}
}
- private void updateInterfaceState(String iface, boolean up) {
- updateInterfaceState(iface, up, new EthernetCallback(null /* cb */));
- }
-
- // TODO(b/225315248): enable/disableInterface() should not affect link state.
- private void updateInterfaceState(String iface, boolean up, EthernetCallback cb) {
- final int mode = getInterfaceMode(iface);
- if (mode == INTERFACE_MODE_SERVER || !mFactory.hasInterface(iface)) {
- // The interface is in server mode or is not tracked.
- cb.onError("Failed to set link state " + (up ? "up" : "down") + " for " + iface);
+ private void setInterfaceAdministrativeState(String iface, boolean up, EthernetCallback cb) {
+ if (getInterfaceState(iface) == EthernetManager.STATE_ABSENT) {
+ cb.onError("Failed to enable/disable absent interface: " + iface);
+ return;
+ }
+ if (getInterfaceRole(iface) == EthernetManager.ROLE_SERVER) {
+ // TODO: support setEthernetState for server mode interfaces.
+ cb.onError("Failed to enable/disable interface in server mode: " + iface);
return;
}
+ if (up) {
+ // WARNING! setInterfaceUp() clears the IPv4 address and readds it. Calling
+ // enableInterface() on an active interface can lead to a provisioning failure which
+ // will cause IpClient to be restarted.
+ // TODO: use netlink directly rather than calling into netd.
+ NetdUtils.setInterfaceUp(mNetd, iface);
+ } else {
+ NetdUtils.setInterfaceDown(mNetd, iface);
+ }
+ cb.onResult(iface);
+ }
+
+ private void updateInterfaceState(String iface, boolean up) {
+ final int mode = getInterfaceMode(iface);
+ if (mode == INTERFACE_MODE_SERVER) {
+ // TODO: support tracking link state for interfaces in server mode.
+ return;
+ }
+
+ // If updateInterfaceLinkState returns false, the interface is already in the correct state.
if (mFactory.updateInterfaceLinkState(iface, up)) {
broadcastInterfaceStateChange(iface);
}
- // If updateInterfaceLinkState returns false, the interface is already in the correct state.
- // Always return success.
- cb.onResult(iface);
}
private void maybeUpdateServerModeInterfaceState(String iface, boolean available) {
diff --git a/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt b/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt
index b7e5205..7af3c83 100644
--- a/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt
+++ b/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt
@@ -899,6 +899,20 @@
}
@Test
+ fun testEnableDisableInterface_callbacks() {
+ val iface = createInterface()
+ val listener = EthernetStateListener()
+ addInterfaceStateListener(listener)
+ listener.expectCallback(iface, STATE_LINK_UP, ROLE_CLIENT)
+
+ disableInterface(iface).expectResult(iface.name)
+ listener.expectCallback(iface, STATE_LINK_DOWN, ROLE_CLIENT)
+
+ enableInterface(iface).expectResult(iface.name)
+ listener.expectCallback(iface, STATE_LINK_UP, ROLE_CLIENT)
+ }
+
+ @Test
fun testUpdateConfiguration_forBothIpConfigAndCapabilities() {
val iface = createInterface()
val cb = requestNetwork(ETH_REQUEST.copyWithEthernetSpecifier(iface.name))