Handle missing parent interfaces

While this does not fix having inconsistent interfaces, at least we
don't fail enumerating them. With this change we still return these
children interfaces without parent set.

Bug: 159277702
Test: atest CtsLibcoreTestCases:libcore.java.net.NetworkInterfaceTest
Change-Id: Ibbe1f273683eb169a0e96425a2c21c5072bf19d7
Merged-In: Ibbe1f273683eb169a0e96425a2c21c5072bf19d7
diff --git a/luni/src/test/java/libcore/java/net/NetworkInterfaceTest.java b/luni/src/test/java/libcore/java/net/NetworkInterfaceTest.java
index f0f79ad..8375421 100644
--- a/luni/src/test/java/libcore/java/net/NetworkInterfaceTest.java
+++ b/luni/src/test/java/libcore/java/net/NetworkInterfaceTest.java
@@ -17,6 +17,7 @@
 package libcore.java.net;
 
 import junit.framework.TestCase;
+import org.mockito.Mockito;
 
 import android.system.StructIfaddrs;
 import java.io.BufferedReader;
@@ -39,6 +40,7 @@
 import java.util.regex.Pattern;
 import libcore.io.IoUtils;
 import libcore.io.Libcore;
+import libcore.io.Os;
 
 import static android.system.OsConstants.AF_INET;
 import static android.system.OsConstants.IFF_LOOPBACK;
@@ -48,6 +50,7 @@
 import static android.system.OsConstants.IFF_UP;
 import static android.system.OsConstants.SOCK_DGRAM;
 import static java.net.NetworkInterface.getNetworkInterfaces;
+import static org.mockito.ArgumentMatchers.anyString;
 
 public class NetworkInterfaceTest extends TestCase {
     // http://code.google.com/p/android/issues/detail?id=13784
@@ -221,6 +224,29 @@
         assertEquals(ifaddrsNames, actualNiNames);
     }
 
+    // Validate that we don't fail to enumerate interfaces if there is virtual interface without parent interface present.
+    // b/159277702
+    public void testGetNetworkInterfaces_OrphanInterfaceDoesNotThrow() throws Exception {
+        Os originalOs = Libcore.getOs();
+        Os mockOs = Mockito.mock(Os.class);
+
+        try {
+            Mockito.when(mockOs.getifaddrs()).thenReturn(new StructIfaddrs[] {
+                new StructIfaddrs("dummy0:1", 0, null, null, null, null),
+            });
+
+            Mockito.when(mockOs.if_nametoindex(anyString())).thenReturn(1);
+
+            assertTrue("Failed to swap OS implementation", Libcore.compareAndSetOs(originalOs, mockOs));
+
+            Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
+            assertEquals(1, Collections.list(interfaces).size());
+        }
+        finally {
+            assertTrue("Failed to revert OS implementation", Libcore.compareAndSetOs(mockOs, originalOs));
+        }
+    }
+
     // Calling getSubInterfaces on interfaces with no subinterface should not throw NPE.
     // http://b/33844501
     public void testGetSubInterfaces() throws Exception {
diff --git a/ojluni/src/main/java/java/net/NetworkInterface.java b/ojluni/src/main/java/java/net/NetworkInterface.java
index a30b6bf..e56e0cb 100644
--- a/ojluni/src/main/java/java/net/NetworkInterface.java
+++ b/ojluni/src/main/java/java/net/NetworkInterface.java
@@ -494,8 +494,11 @@
                 NetworkInterface parent = nis.get(parentName);
 
                 ni.virtual = true;
-                ni.parent = parent;
-                parent.childs.add(ni);
+
+                if (parent != null) {
+                    ni.parent = parent;
+                    parent.childs.add(ni);
+                }
             }
         }