[Thread] add vendor & model name support for net diag

1. allow OEMs to default the vendor and model name to system properties.
2. use the vendor & model name for net diag TLVs

Change-Id: I30e988ba3e9cb9f9c5dc3a096f162d5dbcdfbc11
diff --git a/service/ServiceConnectivityResources/res/values/config_thread.xml b/service/ServiceConnectivityResources/res/values/config_thread.xml
index a458c7f..62b12fb 100644
--- a/service/ServiceConnectivityResources/res/values/config_thread.xml
+++ b/service/ServiceConnectivityResources/res/values/config_thread.xml
@@ -46,11 +46,12 @@
     <bool name="config_thread_location_use_for_country_code_enabled">true</bool>
 
     <!-- Specifies the UTF-8 vendor name of this device. If this value is not an empty string, it
-    will be included in TXT value (key is 'vn') of the "_meshcop._udp" mDNS service which is
-    published by the Thread service. A non-empty string value must not exceed length of 24 UTF-8
-    bytes.
+    will be included in TXT value (key is 'vn') of the "_meshcop._udp" mDNS service as well as the
+    Vendor Name TLV for network diagnostic. A non-empty string value must not exceed length of 24
+    UTF-8 bytes. A special value "ro.product.manufacturer" indicates this value should be derived
+    from the `ro.product.manufacturer` system property.
     -->
-    <string translatable="false" name="config_thread_vendor_name">Android</string>
+    <string translatable="false" name="config_thread_vendor_name">ro.product.manufacturer</string>
 
     <!-- Specifies the 24 bits vendor OUI of this device. If this value is not an empty string, it
     will be included in TXT (key is 'vo') value of the "_meshcop._udp" mDNS service which is
@@ -61,11 +62,12 @@
     <string translatable="false" name="config_thread_vendor_oui"></string>
 
     <!-- Specifies the UTF-8 product model name of this device. If this value is not an empty
-    string, it will be included in TXT (key is 'mn') value of the "_meshcop._udp" mDNS service
-    which is published by the Thread service. A non-empty string value must not exceed length of 24
-    UTF-8 bytes.
+    string, it will be included in TXT (key is 'mn') value of the "_meshcop._udp" mDNS service as
+    well as the Vendor Model TLV for network diagnostic. A non-empty string value must not exceed
+    length of 24 UTF-8 bytes. A special value "ro.product.model" indicates this value should be
+    derived from the `ro.product.model` system property.
     -->
-    <string translatable="false" name="config_thread_model_name">Thread Border Router</string>
+    <string translatable="false" name="config_thread_model_name">ro.product.model</string>
 
     <!-- Specifies vendor-specific mDNS TXT entries which will be included in the "_meshcop._udp"
     service. The TXT entries list MUST conform to the format requirement in RFC 6763 section 6. For
diff --git a/thread/service/java/com/android/server/thread/ThreadNetworkControllerService.java b/thread/service/java/com/android/server/thread/ThreadNetworkControllerService.java
index d859fb2..e99c88e 100644
--- a/thread/service/java/com/android/server/thread/ThreadNetworkControllerService.java
+++ b/thread/service/java/com/android/server/thread/ThreadNetworkControllerService.java
@@ -128,6 +128,7 @@
 import com.android.net.module.util.SharedLog;
 import com.android.server.ServiceManagerWrapper;
 import com.android.server.connectivity.ConnectivityResources;
+import com.android.server.connectivity.MockableSystemProperties;
 import com.android.server.thread.openthread.BackboneRouterState;
 import com.android.server.thread.openthread.DnsTxtAttribute;
 import com.android.server.thread.openthread.IChannelMasksReceiver;
@@ -191,6 +192,7 @@
 
     private final Context mContext;
     private final Handler mHandler;
+    private final MockableSystemProperties mSystemProperties;
 
     // Below member fields can only be accessed from the handler thread (`mHandler`). In
     // particular, the constructor does not run on the handler thread, so it must not touch any of
@@ -235,6 +237,7 @@
     ThreadNetworkControllerService(
             Context context,
             Handler handler,
+            MockableSystemProperties systemProperties,
             NetworkProvider networkProvider,
             Supplier<IOtDaemon> otDaemonSupplier,
             ConnectivityManager connectivityManager,
@@ -249,6 +252,7 @@
             Map<Network, LinkProperties> networkToLinkProperties) {
         mContext = context;
         mHandler = handler;
+        mSystemProperties = systemProperties;
         mNetworkProvider = networkProvider;
         mOtDaemonSupplier = otDaemonSupplier;
         mConnectivityManager = connectivityManager;
@@ -286,6 +290,7 @@
         return new ThreadNetworkControllerService(
                 context,
                 handler,
+                new MockableSystemProperties(),
                 networkProvider,
                 () -> IOtDaemon.Stub.asInterface(ServiceManagerWrapper.waitForService("ot_daemon")),
                 connectivityManager,
@@ -355,7 +360,7 @@
                 newOtDaemonConfig(mPersistentSettings.getConfiguration()),
                 mTunIfController.getTunFd(),
                 mNsdPublisher,
-                getMeshcopTxtAttributes(mResources.get()),
+                getMeshcopTxtAttributes(mResources.get(), mSystemProperties),
                 mCountryCodeSupplier.get(),
                 FeatureFlags.isTrelEnabled(),
                 mOtDaemonCallbackProxy);
@@ -365,10 +370,37 @@
         return mOtDaemon;
     }
 
+    static String getVendorName(Resources resources, MockableSystemProperties systemProperties) {
+        final String PROP_MANUFACTURER = "ro.product.manufacturer";
+        String vendorName = resources.getString(R.string.config_thread_vendor_name);
+        if (vendorName.equalsIgnoreCase(PROP_MANUFACTURER)) {
+            vendorName = systemProperties.get(PROP_MANUFACTURER);
+            // Assume it's always ASCII chars in ro.product.manufacturer
+            if (vendorName.length() > MAX_VENDOR_NAME_UTF8_BYTES) {
+                vendorName = vendorName.substring(0, MAX_VENDOR_NAME_UTF8_BYTES);
+            }
+        }
+        return vendorName;
+    }
+
+    static String getModelName(Resources resources, MockableSystemProperties systemProperties) {
+        final String PROP_MODEL = "ro.product.model";
+        String modelName = resources.getString(R.string.config_thread_model_name);
+        if (modelName.equalsIgnoreCase(PROP_MODEL)) {
+            modelName = systemProperties.get(PROP_MODEL);
+            // Assume it's always ASCII chars in ro.product.model
+            if (modelName.length() > MAX_MODEL_NAME_UTF8_BYTES) {
+                modelName = modelName.substring(0, MAX_MODEL_NAME_UTF8_BYTES);
+            }
+        }
+        return modelName;
+    }
+
     @VisibleForTesting
-    static MeshcopTxtAttributes getMeshcopTxtAttributes(Resources resources) {
-        final String modelName = resources.getString(R.string.config_thread_model_name);
-        final String vendorName = resources.getString(R.string.config_thread_vendor_name);
+    static MeshcopTxtAttributes getMeshcopTxtAttributes(
+            Resources resources, MockableSystemProperties systemProperties) {
+        final String vendorName = getVendorName(resources, systemProperties);
+        final String modelName = getModelName(resources, systemProperties);
         final String vendorOui = resources.getString(R.string.config_thread_vendor_oui);
         final String[] vendorSpecificTxts =
                 resources.getStringArray(R.array.config_thread_mdns_vendor_specific_txts);
@@ -637,6 +669,8 @@
                 .setSrpServerWaitForBorderRoutingEnabled(srpServerWaitEnabled)
                 .setBorderRouterAutoJoinEnabled(autoJoinEnabled)
                 .setCountryCodeEnabled(countryCodeEnabled)
+                .setVendorName(getVendorName(mResources.get(), mSystemProperties))
+                .setModelName(getModelName(mResources.get(), mSystemProperties))
                 .build();
     }
 
diff --git a/thread/tests/integration/src/android/net/thread/ServiceDiscoveryTest.java b/thread/tests/integration/src/android/net/thread/ServiceDiscoveryTest.java
index c4e373a..a9c0da2 100644
--- a/thread/tests/integration/src/android/net/thread/ServiceDiscoveryTest.java
+++ b/thread/tests/integration/src/android/net/thread/ServiceDiscoveryTest.java
@@ -48,6 +48,7 @@
 import android.net.thread.utils.ThreadFeatureCheckerRule.RequiresThreadFeature;
 import android.net.thread.utils.ThreadNetworkControllerWrapper;
 import android.os.HandlerThread;
+import android.os.SystemProperties;
 
 import androidx.test.core.app.ApplicationProvider;
 import androidx.test.filters.LargeTest;
@@ -454,14 +455,22 @@
     }
 
     @Test
-    public void meshcopOverlay_vendorAndModelNameAreSetToOverlayValue() throws Exception {
+    public void meshcopOverlay_vendorAndModelNameAreSetToSystemProperties() throws Exception {
         NsdServiceInfo discoveredService = discoverService(mNsdManager, "_meshcop._udp");
         assertThat(discoveredService).isNotNull();
         NsdServiceInfo meshcopService = resolveService(mNsdManager, discoveredService);
+        String expectedVendorName = SystemProperties.get("ro.product.manufacturer");
+        if (expectedVendorName.length() > 24) {
+            expectedVendorName = expectedVendorName.substring(0, 24);
+        }
+        String expectedModelName = SystemProperties.get("ro.product.model");
+        if (expectedModelName.length() > 24) {
+            expectedModelName = expectedModelName.substring(0, 24);
+        }
 
         Map<String, byte[]> txtMap = meshcopService.getAttributes();
-        assertThat(txtMap.get("vn")).isEqualTo("Android".getBytes(UTF_8));
-        assertThat(txtMap.get("mn")).isEqualTo("Thread Border Router".getBytes(UTF_8));
+        assertThat(txtMap.get("vn")).isEqualTo(expectedVendorName.getBytes(UTF_8));
+        assertThat(txtMap.get("mn")).isEqualTo(expectedModelName.getBytes(UTF_8));
     }
 
     @Test
diff --git a/thread/tests/integration/src/android/net/thread/ThreadIntegrationTest.java b/thread/tests/integration/src/android/net/thread/ThreadIntegrationTest.java
index b608c5d..c56db02 100644
--- a/thread/tests/integration/src/android/net/thread/ThreadIntegrationTest.java
+++ b/thread/tests/integration/src/android/net/thread/ThreadIntegrationTest.java
@@ -24,6 +24,8 @@
 import static android.net.thread.utils.IntegrationTestUtils.getIpv6Addresses;
 import static android.net.thread.utils.IntegrationTestUtils.getIpv6LinkAddresses;
 import static android.net.thread.utils.IntegrationTestUtils.waitFor;
+import static android.net.thread.utils.OtDaemonController.DIAG_VENDOR_MODEL_TLV_TYPE;
+import static android.net.thread.utils.OtDaemonController.DIAG_VENDOR_NAME_TLV_TYPE;
 import static android.net.thread.utils.ThreadNetworkControllerWrapper.JOIN_TIMEOUT;
 import static android.os.SystemClock.elapsedRealtime;
 
@@ -290,6 +292,17 @@
         // TODO: b/376217403 - enables / disables Border Agent at runtime
     }
 
+    @Test
+    public void networkDiagnostic_vendorAndModelNameAreSet() throws Exception {
+        mController.joinAndWait(DEFAULT_DATASET);
+
+        var tlvTypes = List.of(DIAG_VENDOR_NAME_TLV_TYPE, DIAG_VENDOR_MODEL_TLV_TYPE);
+        var result = mOtCtl.netDiagGet(mOtCtl.getMlEid(), tlvTypes);
+
+        assertThat(result.get("Vendor Name")).isNotEmpty();
+        assertThat(result.get("Vendor Model")).isNotEmpty();
+    }
+
     private NetworkCapabilities registerNetworkCallbackAndWait(NetworkRequest request)
             throws Exception {
         CompletableFuture<Network> networkFuture = new CompletableFuture<>();
diff --git a/thread/tests/unit/src/com/android/server/thread/ThreadNetworkControllerServiceTest.java b/thread/tests/unit/src/com/android/server/thread/ThreadNetworkControllerServiceTest.java
index 63d6130..a73390c 100644
--- a/thread/tests/unit/src/com/android/server/thread/ThreadNetworkControllerServiceTest.java
+++ b/thread/tests/unit/src/com/android/server/thread/ThreadNetworkControllerServiceTest.java
@@ -34,6 +34,7 @@
 import static android.net.thread.ThreadNetworkManager.PERMISSION_THREAD_NETWORK_PRIVILEGED;
 import static android.net.thread.ThreadNetworkManager.PERMISSION_THREAD_NETWORK_TESTING;
 
+import static com.android.server.thread.ThreadNetworkControllerService.getMeshcopTxtAttributes;
 import static com.android.server.thread.ThreadNetworkCountryCode.DEFAULT_COUNTRY_CODE;
 import static com.android.server.thread.ThreadPersistentSettings.KEY_THREAD_ENABLED;
 import static com.android.server.thread.openthread.IOtDaemon.ErrorCode.OT_ERROR_INVALID_STATE;
@@ -49,8 +50,6 @@
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.ArgumentMatchers.isNotNull;
-import static org.mockito.ArgumentMatchers.isNull;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.clearInvocations;
@@ -101,10 +100,10 @@
 import com.android.dx.mockito.inline.extended.ExtendedMockito;
 import com.android.net.module.util.RoutingCoordinatorManager;
 import com.android.server.connectivity.ConnectivityResources;
+import com.android.server.connectivity.MockableSystemProperties;
 import com.android.server.thread.openthread.DnsTxtAttribute;
 import com.android.server.thread.openthread.IOtStatusReceiver;
 import com.android.server.thread.openthread.MeshcopTxtAttributes;
-import com.android.server.thread.openthread.OtDaemonConfiguration;
 import com.android.server.thread.openthread.testing.FakeOtDaemon;
 
 import org.junit.After;
@@ -181,6 +180,7 @@
     private static final String TEST_MODEL_NAME = "test model";
     private static final LinkAddress TEST_NAT64_CIDR = new LinkAddress("192.168.255.0/24");
 
+    @Mock private MockableSystemProperties mMockSystemProperties;
     @Mock private ConnectivityManager mMockConnectivityManager;
     @Mock private RoutingCoordinatorManager mMockRoutingCoordinatorManager;
     @Mock private NetworkAgent mMockNetworkAgent;
@@ -271,6 +271,7 @@
                 new ThreadNetworkControllerService(
                         mContext,
                         handler,
+                        mMockSystemProperties,
                         networkProvider,
                         () -> mFakeOtDaemon,
                         mMockConnectivityManager,
@@ -336,6 +337,23 @@
     }
 
     @Test
+    public void initialize_vendorAndModelNameSetToProperty_propertiesAreSetToOtDaemon()
+            throws Exception {
+        when(mMockSystemProperties.get(eq("ro.product.manufacturer"))).thenReturn("Banana");
+        when(mResources.getString(eq(R.string.config_thread_vendor_name)))
+                .thenReturn("ro.product.manufacturer");
+        when(mMockSystemProperties.get(eq("ro.product.model"))).thenReturn("Orange");
+        when(mResources.getString(eq(R.string.config_thread_model_name)))
+                .thenReturn("ro.product.model");
+
+        mService.initialize();
+        mTestLooper.dispatchAll();
+
+        assertThat(mFakeOtDaemon.getConfiguration().vendorName).isEqualTo("Banana");
+        assertThat(mFakeOtDaemon.getConfiguration().modelName).isEqualTo("Orange");
+    }
+
+    @Test
     public void initialize_nat64Disabled_doesNotRequestNat64CidrAndConfiguresOtDaemon()
             throws Exception {
         ThreadConfiguration config =
@@ -345,8 +363,7 @@
         mTestLooper.dispatchAll();
 
         verify(mMockRoutingCoordinatorManager, never()).requestDownstreamAddress(any());
-        verify(mFakeOtDaemon, times(1)).setNat64Cidr(isNull(), any());
-        verify(mFakeOtDaemon, never()).setNat64Cidr(isNotNull(), any());
+        assertThat(mFakeOtDaemon.getNat64Cidr()).isNull();
     }
 
     @Test
@@ -359,11 +376,8 @@
         mTestLooper.dispatchAll();
 
         verify(mMockRoutingCoordinatorManager, times(1)).requestDownstreamAddress(any());
-        verify(mFakeOtDaemon, times(1))
-                .setConfiguration(
-                        new OtDaemonConfiguration.Builder().setNat64Enabled(true).build(),
-                        null /* receiver */);
-        verify(mFakeOtDaemon, times(1)).setNat64Cidr(eq(TEST_NAT64_CIDR.toString()), any());
+        assertThat(mFakeOtDaemon.getConfiguration().nat64Enabled).isTrue();
+        assertThat(mFakeOtDaemon.getNat64Cidr()).isEqualTo(TEST_NAT64_CIDR.toString());
     }
 
     @Test
@@ -400,7 +414,7 @@
         when(mResources.getString(eq(R.string.config_thread_vendor_name))).thenReturn("");
 
         MeshcopTxtAttributes meshcopTxts =
-                ThreadNetworkControllerService.getMeshcopTxtAttributes(mResources);
+                getMeshcopTxtAttributes(mResources, mMockSystemProperties);
 
         assertThat(meshcopTxts.vendorName).isEqualTo("");
     }
@@ -412,7 +426,31 @@
 
         assertThrows(
                 IllegalStateException.class,
-                () -> ThreadNetworkControllerService.getMeshcopTxtAttributes(mResources));
+                () -> getMeshcopTxtAttributes(mResources, mMockSystemProperties));
+    }
+
+    @Test
+    public void getMeshcopTxtAttributes_VendorNameSetToManufacturer_manufacturerPropertyIsUsed() {
+        when(mMockSystemProperties.get(eq("ro.product.manufacturer"))).thenReturn("Banana");
+        when(mResources.getString(eq(R.string.config_thread_vendor_name)))
+                .thenReturn("ro.product.manufacturer");
+
+        MeshcopTxtAttributes meshcopTxts =
+                getMeshcopTxtAttributes(mResources, mMockSystemProperties);
+
+        assertThat(meshcopTxts.vendorName).isEqualTo("Banana");
+    }
+
+    @Test
+    public void getMeshcopTxtAttributes_ModelNameSetToModelProperty_modelPropertyIsUsed() {
+        when(mMockSystemProperties.get(eq("ro.product.model"))).thenReturn("Orange");
+        when(mResources.getString(eq(R.string.config_thread_model_name)))
+                .thenReturn("ro.product.model");
+
+        MeshcopTxtAttributes meshcopTxts =
+                getMeshcopTxtAttributes(mResources, mMockSystemProperties);
+
+        assertThat(meshcopTxts.modelName).isEqualTo("Orange");
     }
 
     @Test
@@ -422,14 +460,14 @@
 
         assertThrows(
                 IllegalStateException.class,
-                () -> ThreadNetworkControllerService.getMeshcopTxtAttributes(mResources));
+                () -> getMeshcopTxtAttributes(mResources, mMockSystemProperties));
     }
 
     @Test
     public void getMeshcopTxtAttributes_emptyModelName_accepted() {
         when(mResources.getString(eq(R.string.config_thread_model_name))).thenReturn("");
 
-        var meshcopTxts = ThreadNetworkControllerService.getMeshcopTxtAttributes(mResources);
+        var meshcopTxts = getMeshcopTxtAttributes(mResources, mMockSystemProperties);
         assertThat(meshcopTxts.modelName).isEqualTo("");
     }
 
@@ -461,7 +499,7 @@
 
     private byte[] getMeshcopTxtAttributesWithVendorOui(String vendorOui) {
         when(mResources.getString(eq(R.string.config_thread_vendor_oui))).thenReturn(vendorOui);
-        return ThreadNetworkControllerService.getMeshcopTxtAttributes(mResources).vendorOui;
+        return getMeshcopTxtAttributes(mResources, mMockSystemProperties).vendorOui;
     }
 
     @Test
@@ -886,16 +924,12 @@
 
         verify(mockReceiver, times(1)).onSuccess();
         verify(mMockRoutingCoordinatorManager, times(1)).requestDownstreamAddress(any());
-        verify(mFakeOtDaemon, times(1))
-                .setConfiguration(
-                        eq(new OtDaemonConfiguration.Builder().setNat64Enabled(true).build()),
-                        any(IOtStatusReceiver.class));
-        verify(mFakeOtDaemon, times(1))
-                .setNat64Cidr(eq(TEST_NAT64_CIDR.toString()), any(IOtStatusReceiver.class));
+        assertThat(mFakeOtDaemon.getConfiguration().nat64Enabled).isTrue();
+        assertThat(mFakeOtDaemon.getNat64Cidr()).isEqualTo(TEST_NAT64_CIDR.toString());
     }
 
     @Test
-    public void setConfiguration_enablesNat64_otDaemonRemoteFailure_serviceDoesNotCrash()
+    public void setConfiguration_enablesNat64AndOtDaemonRemoteFailure_serviceDoesNotCrash()
             throws Exception {
         mService.initialize();
         mTestLooper.dispatchAll();
@@ -929,12 +963,8 @@
         verify(mockReceiver, times(1)).onSuccess();
         verify(mMockRoutingCoordinatorManager, times(1)).releaseDownstream(any());
         verify(mMockRoutingCoordinatorManager, never()).requestDownstreamAddress(any());
-        verify(mFakeOtDaemon, times(1))
-                .setConfiguration(
-                        eq(new OtDaemonConfiguration.Builder().setNat64Enabled(false).build()),
-                        any(IOtStatusReceiver.class));
-        verify(mFakeOtDaemon, times(1)).setNat64Cidr(isNull(), any(IOtStatusReceiver.class));
-        verify(mFakeOtDaemon, never()).setNat64Cidr(isNotNull(), any(IOtStatusReceiver.class));
+        assertThat(mFakeOtDaemon.getConfiguration().nat64Enabled).isFalse();
+        assertThat(mFakeOtDaemon.getNat64Cidr()).isNull();
     }
 
     @Test
diff --git a/thread/tests/utils/src/android/net/thread/utils/OtDaemonController.java b/thread/tests/utils/src/android/net/thread/utils/OtDaemonController.java
index d35b94e..41d9eaf 100644
--- a/thread/tests/utils/src/android/net/thread/utils/OtDaemonController.java
+++ b/thread/tests/utils/src/android/net/thread/utils/OtDaemonController.java
@@ -24,10 +24,13 @@
 import com.android.compatibility.common.util.SystemUtil;
 
 import java.net.Inet6Address;
+import java.net.InetAddress;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.stream.Collectors;
 
 /**
@@ -37,6 +40,9 @@
  * <p>Note that this class takes root privileged to run.
  */
 public final class OtDaemonController {
+    public static final int DIAG_VENDOR_NAME_TLV_TYPE = 25;
+    public static final int DIAG_VENDOR_MODEL_TLV_TYPE = 26;
+
     private static final String OT_CTL = "/system/bin/ot-ctl";
 
     /**
@@ -188,6 +194,35 @@
     }
 
     /**
+     * Sends DIAG_GET request to the given peer device and returns the parsed result as a dict of
+     * the requested TLV values.
+     *
+     * <p>For example, a request {@code netDiagGet("fdad:3d13:7b11:4049:ed1a:7e87:4770:a345",
+     * [DIAG_VENDOR_NAME_TLV_TYPE, DIAG_VENDOR_MODEL_TLV_TYPE])} can return a dict of {@code
+     * {"Vendor Name" : "ABC", "Vendor Model" : "Cuttlefish"}}
+     */
+    public Map<String, String> netDiagGet(InetAddress peerAddr, List<Integer> tlvTypes) {
+        String tlvTypeList =
+                tlvTypes.stream().map(Object::toString).collect(Collectors.joining(" "));
+
+        List<String> outputs =
+                executeCommandAndParse(
+                        "networkdiagnostic get " + peerAddr.getHostAddress() + " " + tlvTypeList);
+        Map<String, String> result = new HashMap<>();
+        for (String line : outputs) {
+            if (line.startsWith("DIAG_GET")) {
+                continue;
+            }
+            String[] keyValue = line.split(":");
+            if (keyValue.length != 2) {
+                throw new IllegalStateException("Unexpected OT output: " + line);
+            }
+            result.put(keyValue[0].strip(), keyValue[1].strip());
+        }
+        return result;
+    }
+
+    /**
      * Executes a ot-ctl command and parse the output to a list of strings.
      *
      * <p>The trailing "Done" in the command output will be dropped.
diff --git a/thread/tests/utils/src/android/net/thread/utils/TapTestNetworkTracker.java b/thread/tests/utils/src/android/net/thread/utils/TapTestNetworkTracker.java
index 9a1a05b..62c2785 100644
--- a/thread/tests/utils/src/android/net/thread/utils/TapTestNetworkTracker.java
+++ b/thread/tests/utils/src/android/net/thread/utils/TapTestNetworkTracker.java
@@ -16,44 +16,23 @@
 package android.net.thread.utils;
 
 import static android.Manifest.permission.MANAGE_TEST_NETWORKS;
-import static android.net.InetAddresses.parseNumericAddress;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED;
-import static android.net.NetworkCapabilities.TRANSPORT_TEST;
-import static android.system.OsConstants.AF_INET6;
-import static android.system.OsConstants.IPPROTO_UDP;
-import static android.system.OsConstants.SOCK_DGRAM;
 
 import static com.android.testutils.RecorderCallback.CallbackEntry.LINK_PROPERTIES_CHANGED;
 import static com.android.testutils.TestPermissionUtil.runAsShell;
 
 import android.content.Context;
 import android.net.ConnectivityManager;
-import android.net.LinkAddress;
 import android.net.LinkProperties;
 import android.net.Network;
-import android.net.NetworkAgentConfig;
-import android.net.NetworkCapabilities;
-import android.net.NetworkRequest;
 import android.net.TestNetworkInterface;
 import android.net.TestNetworkManager;
-import android.net.TestNetworkSpecifier;
 import android.os.Looper;
-import android.system.ErrnoException;
-import android.system.Os;
 
-import com.android.compatibility.common.util.PollingCheck;
 import com.android.testutils.TestableNetworkAgent;
 import com.android.testutils.TestableNetworkCallback;
 
-import java.io.FileDescriptor;
 import java.io.IOException;
-import java.net.InterfaceAddress;
-import java.net.NetworkInterface;
-import java.net.SocketException;
 import java.time.Duration;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
 
 /** A class that can create/destroy a test network based on TAP interface. */
 public final class TapTestNetworkTracker {