Merge "Use NetworkInterface API to retrieve interface list in EthernetTracker" into main am: 00f03cd550

Original change: https://android-review.googlesource.com/c/platform/packages/modules/Connectivity/+/3382165

Change-Id: Ib94135b9424722d89331591675d0e0fec86f727b
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java
index b8689d6..21b9b1d 100644
--- a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java
+++ b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java
@@ -317,6 +317,6 @@
     @Override
     public List<String> getInterfaceList() {
         PermissionUtils.enforceAccessNetworkStatePermission(mContext, TAG);
-        return mTracker.getInterfaceList();
+        return mTracker.getEthernetInterfaceList();
     }
 }
diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java
index 5228aab..adfb694 100644
--- a/service-t/src/com/android/server/ethernet/EthernetTracker.java
+++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java
@@ -40,7 +40,6 @@
 import android.os.Handler;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
-import android.os.ServiceSpecificException;
 import android.system.OsConstants;
 import android.text.TextUtils;
 import android.util.ArrayMap;
@@ -62,7 +61,10 @@
 
 import java.io.FileDescriptor;
 import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
 import java.util.ArrayList;
+import java.util.Enumeration;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Objects;
@@ -105,7 +107,7 @@
 
     /**
      * Track test interfaces if true, don't track otherwise.
-     * Volatile is needed as getInterfaceList() does not run on the handler thread.
+     * Volatile is needed as getEthernetInterfaceList() does not run on the handler thread.
      */
     private volatile boolean mIncludeTestInterfaces = false;
 
@@ -398,26 +400,27 @@
         return mFactory.getAvailableInterfaces(includeRestricted);
     }
 
-    List<String> getInterfaceList() {
+    List<String> getEthernetInterfaceList() {
         final List<String> interfaceList = new ArrayList<String>();
-        final String[] ifaces;
+        final Enumeration<NetworkInterface> ifaces;
         try {
-            ifaces = mNetd.interfaceGetList();
-        } catch (RemoteException e) {
-            Log.e(TAG, "Could not get list of interfaces " + e);
+            ifaces = NetworkInterface.getNetworkInterfaces();
+        } catch (SocketException e) {
+            Log.e(TAG, "Failed to get ethernet interfaces: ", e);
             return interfaceList;
         }
 
         // There is a possible race with setIncludeTestInterfaces() which can affect
         // isValidEthernetInterface (it returns true for test interfaces if setIncludeTestInterfaces
         // is set to true).
-        // setIncludeTestInterfaces() is only used in tests, and since getInterfaceList() does not
-        // run on the handler thread, the behavior around setIncludeTestInterfaces() is
+        // setIncludeTestInterfaces() is only used in tests, and since getEthernetInterfaceList()
+        // does not run on the handler thread, the behavior around setIncludeTestInterfaces() is
         // indeterminate either way. This can easily be circumvented by waiting on a callback from
         // a test interface after calling setIncludeTestInterfaces() before calling this function.
         // In production code, this has no effect.
-        for (String iface : ifaces) {
-            if (isValidEthernetInterface(iface)) interfaceList.add(iface);
+        while (ifaces.hasMoreElements()) {
+            NetworkInterface iface = ifaces.nextElement();
+            if (isValidEthernetInterface(iface.getName())) interfaceList.add(iface.getName());
         }
         return interfaceList;
     }
@@ -707,10 +710,6 @@
     }
 
     private void maybeTrackInterface(String iface) {
-        if (!isValidEthernetInterface(iface)) {
-            return;
-        }
-
         // If we don't already track this interface, and if this interface matches
         // our regex, start tracking it.
         if (mFactory.hasInterface(iface) || iface.equals(mTetheringInterface)) {
@@ -730,13 +729,9 @@
     }
 
     private void trackAvailableInterfaces() {
-        try {
-            final String[] ifaces = mNetd.interfaceGetList();
-            for (String iface : ifaces) {
-                maybeTrackInterface(iface);
-            }
-        } catch (RemoteException | ServiceSpecificException e) {
-            Log.e(TAG, "Could not get list of interfaces " + e);
+        final List<String> ifaces = getEthernetInterfaceList();
+        for (String iface : ifaces) {
+            maybeTrackInterface(iface);
         }
     }
 
diff --git a/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt b/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt
index 9be579b..5b2c9f7 100644
--- a/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt
+++ b/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt
@@ -77,6 +77,7 @@
 import com.android.testutils.assertThrows
 import com.android.testutils.runAsShell
 import com.android.testutils.waitForIdle
+import com.google.common.truth.Truth.assertThat
 import java.io.IOException
 import java.net.Inet6Address
 import java.net.Socket
@@ -1089,4 +1090,24 @@
         setEthernetEnabled(true)
         listener.eventuallyExpect(iface, STATE_LINK_UP, ROLE_CLIENT)
     }
+
+    @Test
+    fun testGetInterfaceList_disableEnableEthernet() {
+        // Test that interface list can be obtained when ethernet is disabled.
+        setEthernetEnabled(false)
+        // Create two test interfaces and check the return list contains the interface names.
+        val iface1 = createInterface()
+        val iface2 = createInterface()
+        var ifaces = em.getInterfaceList()
+        assertThat(ifaces).containsAtLeast(iface1.name, iface2.name)
+
+        // Remove one existing test interface and check the return list doesn't contain the
+        // removed interface name.
+        removeInterface(iface1)
+        ifaces = em.getInterfaceList()
+        assertThat(ifaces).doesNotContain(iface1.name)
+        assertThat(ifaces).contains(iface2.name)
+
+        removeInterface(iface2)
+    }
 }