Merge "[Thread] add annotations for unit test NsdPublisherTest" into main
diff --git a/Tethering/res/values-mcc310-mnc004-eu/strings.xml b/Tethering/res/values-mcc310-mnc004-eu/strings.xml
index c970dd7..ff2a505 100644
--- a/Tethering/res/values-mcc310-mnc004-eu/strings.xml
+++ b/Tethering/res/values-mcc310-mnc004-eu/strings.xml
@@ -18,7 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="no_upstream_notification_title" msgid="3584617491053416666">"Konexioa partekatzeko aukerak ez du Interneteko konexiorik"</string>
     <string name="no_upstream_notification_message" msgid="5626323795587558017">"Ezin dira konektatu gailuak"</string>
-    <string name="no_upstream_notification_disable_button" msgid="868677179945695858">"Desaktibatu konexioa partekatzeko aukera"</string>
+    <string name="no_upstream_notification_disable_button" msgid="868677179945695858">"Desaktibatu konexioa partekatzea"</string>
     <string name="upstream_roaming_notification_title" msgid="2870229486619751829">"Wifi-gunea edo konexioa partekatzeko aukera aktibatuta dago"</string>
     <string name="upstream_roaming_notification_message" msgid="5229740963392849544">"Baliteke tarifa gehigarriak ordaindu behar izatea ibiltaritza erabili bitartean"</string>
 </resources>
diff --git a/Tethering/tests/integration/base/android/net/EthernetTetheringTestBase.java b/Tethering/tests/integration/base/android/net/EthernetTetheringTestBase.java
index 120b871..9ab39bf 100644
--- a/Tethering/tests/integration/base/android/net/EthernetTetheringTestBase.java
+++ b/Tethering/tests/integration/base/android/net/EthernetTetheringTestBase.java
@@ -42,7 +42,6 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.junit.Assume.assumeFalse;
@@ -105,7 +104,7 @@
     // Used to check if any tethering interface is available. Choose 200ms to be request timeout
     // because the average interface requested time on cuttlefish@acloud is around 10ms.
     // See TetheredInterfaceRequester.getInterface, isInterfaceForTetheringAvailable.
-    private static final int AVAILABLE_TETHER_IFACE_REQUEST_TIMEOUT_MS = 200;
+    private static final int SHORT_TIMEOUT_MS = 200;
     private static final int TETHER_REACHABILITY_ATTEMPTS = 20;
     protected static final long WAIT_RA_TIMEOUT_MS = 2000;
 
@@ -154,7 +153,7 @@
     private boolean mRunTests;
     private HandlerThread mHandlerThread;
     private Handler mHandler;
-    private TetheredInterfaceRequester mTetheredInterfaceRequester;
+    protected TetheredInterfaceRequester mTetheredInterfaceRequester;
 
     // Late initialization in initTetheringTester().
     private TapPacketReader mUpstreamReader;
@@ -245,12 +244,14 @@
         maybeUnregisterTetheringEventCallback(mTetheringEventCallback);
         mTetheringEventCallback = null;
 
-        runAsShell(NETWORK_SETTINGS, () -> mTetheredInterfaceRequester.release());
         setIncludeTestInterfaces(false);
     }
 
     @After
     public void tearDown() throws Exception {
+        if (mTetheredInterfaceRequester != null) {
+            mTetheredInterfaceRequester.release();
+        }
         try {
             if (mRunTests) cleanUp();
         } finally {
@@ -263,33 +264,17 @@
         }
     }
 
-    protected static boolean isInterfaceForTetheringAvailable() throws Exception {
-        // Before T, all ethernet interfaces could be used for server mode. Instead of
-        // waiting timeout, just checking whether the system currently has any
-        // ethernet interface is more reliable.
-        if (!SdkLevel.isAtLeastT()) {
-            return runAsShell(CONNECTIVITY_USE_RESTRICTED_NETWORKS, () -> sEm.isAvailable());
-        }
-
+    protected boolean isInterfaceForTetheringAvailable() throws Exception {
         // If previous test case doesn't release tethering interface successfully, the other tests
         // after that test may be skipped as unexcepted.
         // TODO: figure out a better way to check default tethering interface existenion.
-        final TetheredInterfaceRequester requester = new TetheredInterfaceRequester();
-        try {
-            // Use short timeout (200ms) for requesting an existing interface, if any, because
-            // it should reurn faster than requesting a new tethering interface. Using default
-            // timeout (5000ms, TIMEOUT_MS) may make that total testing time is over 1 minute
-            // test module timeout on internal testing.
-            // TODO: if this becomes flaky, consider using default timeout (5000ms) and moving
-            // this check into #setUpOnce.
-            return requester.getInterface(AVAILABLE_TETHER_IFACE_REQUEST_TIMEOUT_MS) != null;
-        } catch (TimeoutException e) {
-            return false;
-        } finally {
-            runAsShell(NETWORK_SETTINGS, () -> {
-                requester.release();
-            });
-        }
+        // Use short timeout (200ms) for requesting an existing interface, if any, because
+        // it should reurn faster than requesting a new tethering interface. Using default
+        // timeout (5000ms, TIMEOUT_MS) may make that total testing time is over 1 minute
+        // test module timeout on internal testing.
+        // TODO: if this becomes flaky, consider using default timeout (5000ms) and moving
+        // this check into #setUpOnce.
+        return mTetheredInterfaceRequester.isPhysicalInterfaceAvailable(SHORT_TIMEOUT_MS);
     }
 
     protected static void setIncludeTestInterfaces(boolean include) {
@@ -304,14 +289,6 @@
         });
     }
 
-    protected String getTetheredInterface() throws Exception {
-        return mTetheredInterfaceRequester.getInterface();
-    }
-
-    protected CompletableFuture<String> requestTetheredInterface() throws Exception {
-        return mTetheredInterfaceRequester.requestInterface();
-    }
-
     protected static void waitForRouterAdvertisement(TapPacketReader reader, String iface,
             long timeoutMs) {
         final long deadline = SystemClock.uptimeMillis() + timeoutMs;
@@ -605,6 +582,11 @@
         private TetheredInterfaceRequest mRequest;
         private final CompletableFuture<String> mFuture = new CompletableFuture<>();
 
+        TetheredInterfaceRequester() {
+            mRequest = runAsShell(NETWORK_SETTINGS, () ->
+                    sEm.requestTetheredInterface(c -> c.run() /* executor */, this));
+        }
+
         @Override
         public void onAvailable(String iface) {
             Log.d(TAG, "Ethernet interface available: " + iface);
@@ -616,28 +598,21 @@
             mFuture.completeExceptionally(new IllegalStateException("onUnavailable received"));
         }
 
-        public CompletableFuture<String> requestInterface() {
-            assertNull("BUG: more than one tethered interface request", mRequest);
-            Log.d(TAG, "Requesting tethered interface");
-            mRequest = runAsShell(NETWORK_SETTINGS, () ->
-                    sEm.requestTetheredInterface(c -> c.run() /* executor */, this));
-            return mFuture;
-        }
-
-        public String getInterface(int timeout) throws Exception {
-            return requestInterface().get(timeout, TimeUnit.MILLISECONDS);
+        public boolean isPhysicalInterfaceAvailable(int timeout) {
+            try {
+                final String iface = mFuture.get(timeout, TimeUnit.MILLISECONDS);
+                return !iface.startsWith("testtap");
+            } catch (Exception e) {
+                return false;
+            }
         }
 
         public String getInterface() throws Exception {
-            return getInterface(TIMEOUT_MS);
+            return mFuture.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
         }
 
         public void release() {
-            if (mRequest != null) {
-                mFuture.obtrudeException(new IllegalStateException("Request already released"));
-                mRequest.release();
-                mRequest = null;
-            }
+            runAsShell(NETWORK_SETTINGS, () -> mRequest.release());
         }
     }
 
@@ -658,7 +633,10 @@
         lp.setLinkAddresses(addresses);
         lp.setDnsServers(dnses);
 
-        return runAsShell(MANAGE_TEST_NETWORKS, () -> initTestNetwork(sContext, lp, TIMEOUT_MS));
+        // TODO: initTestNetwork can take up to 15 seconds on a workstation. Investigate when and
+        // why this is the case. It is unclear whether a 30 second timeout is enough when running
+        // these tests in the much slower test infra.
+        return runAsShell(MANAGE_TEST_NETWORKS, () -> initTestNetwork(sContext, lp, 30_000));
     }
 
     protected void sendDownloadPacketUdp(@NonNull final InetAddress srcIp,
diff --git a/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
index c54d1b4..5c258b2 100644
--- a/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
+++ b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
@@ -59,7 +59,7 @@
 import com.android.testutils.NetworkStackModuleTest;
 import com.android.testutils.TapPacketReader;
 
-import org.junit.BeforeClass;
+import org.junit.After;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -75,8 +75,6 @@
 import java.util.Collection;
 import java.util.List;
 import java.util.Random;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 
 @RunWith(AndroidJUnit4.class)
@@ -151,33 +149,14 @@
             (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04  /* Address: 1.2.3.4 */
     };
 
-    /** Enable/disable tethering once before running the tests. */
-    @BeforeClass
-    public static void setUpOnce() throws Exception {
-        // The first test case may experience tethering restart with IP conflict handling.
-        // Tethering would cache the last upstreams so that the next enabled tethering avoids
-        // picking up the address that is in conflict with the upstreams. To protect subsequent
-        // tests, turn tethering on and off before running them.
-        MyTetheringEventCallback callback = null;
-        TestNetworkInterface testIface = null;
-        assumeTrue(sEm != null);
-        try {
-            // If the physical ethernet interface is available, do nothing.
-            if (isInterfaceForTetheringAvailable()) return;
-
-            testIface = createTestInterface();
-            setIncludeTestInterfaces(true);
-
-            callback = enableEthernetTethering(testIface.getInterfaceName(), null);
-            callback.awaitUpstreamChanged(true /* throwTimeoutException */);
-        } catch (TimeoutException e) {
-            Log.d(TAG, "WARNNING " + e);
-        } finally {
-            maybeCloseTestInterface(testIface);
-            maybeUnregisterTetheringEventCallback(callback);
-
-            setIncludeTestInterfaces(false);
-        }
+    @After
+    public void tearDown() throws Exception {
+        super.tearDown();
+        // TODO: See b/318121782#comment4. Register an ethernet InterfaceStateListener, and wait for
+        // the callback to report client mode. This happens as soon as both
+        // TetheredInterfaceRequester and the tethering code itself have released the interface,
+        // i.e. after stopTethering() has completed.
+        Thread.sleep(3000);
     }
 
     @Test
@@ -201,7 +180,7 @@
             Log.d(TAG, "Including test interfaces");
             setIncludeTestInterfaces(true);
 
-            final String iface = getTetheredInterface();
+            final String iface = mTetheredInterfaceRequester.getInterface();
             assertEquals("TetheredInterfaceCallback for unexpected interface",
                     downstreamIface.getInterfaceName(), iface);
 
@@ -223,8 +202,6 @@
         // This test requires manipulating packets. Skip if there is a physical Ethernet connected.
         assumeFalse(isInterfaceForTetheringAvailable());
 
-        CompletableFuture<String> futureIface = requestTetheredInterface();
-
         setIncludeTestInterfaces(true);
 
         TestNetworkInterface downstreamIface = null;
@@ -234,7 +211,7 @@
         try {
             downstreamIface = createTestInterface();
 
-            final String iface = futureIface.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+            final String iface = mTetheredInterfaceRequester.getInterface();
             assertEquals("TetheredInterfaceCallback for unexpected interface",
                     downstreamIface.getInterfaceName(), iface);
 
@@ -264,7 +241,7 @@
         try {
             downstreamIface = createTestInterface();
 
-            final String iface = getTetheredInterface();
+            final String iface = mTetheredInterfaceRequester.getInterface();
             assertEquals("TetheredInterfaceCallback for unexpected interface",
                     downstreamIface.getInterfaceName(), iface);
 
@@ -338,7 +315,7 @@
         try {
             downstreamIface = createTestInterface();
 
-            final String iface = getTetheredInterface();
+            final String iface = mTetheredInterfaceRequester.getInterface();
             assertEquals("TetheredInterfaceCallback for unexpected interface",
                     downstreamIface.getInterfaceName(), iface);
 
@@ -388,7 +365,7 @@
         MyTetheringEventCallback tetheringEventCallback = null;
         try {
             // Get an interface to use.
-            final String iface = getTetheredInterface();
+            final String iface = mTetheredInterfaceRequester.getInterface();
 
             // Enable Ethernet tethering and check that it starts.
             tetheringEventCallback = enableEthernetTethering(iface, null /* any upstream */);
@@ -509,17 +486,23 @@
         // TODO: test BPF offload maps {rule, stats}.
     }
 
-    // Test network topology:
-    //
-    //         public network (rawip)                 private network
-    //                   |                 UE                |
-    // +------------+    V    +------------+------------+    V    +------------+
-    // |   Sever    +---------+  Upstream  | Downstream +---------+   Client   |
-    // +------------+         +------------+------------+         +------------+
-    // remote ip              public ip                           private ip
-    // 8.8.8.8:443            <Upstream ip>:9876                  <TetheredDevice ip>:9876
-    //
-    private void runUdp4Test() throws Exception {
+
+    /**
+     * Basic IPv4 UDP tethering test. Verify that UDP tethered packets are transferred no matter
+     * using which data path.
+     */
+    @Test
+    public void testTetherUdpV4() throws Exception {
+        // Test network topology:
+        //
+        //         public network (rawip)                 private network
+        //                   |                 UE                |
+        // +------------+    V    +------------+------------+    V    +------------+
+        // |   Sever    +---------+  Upstream  | Downstream +---------+   Client   |
+        // +------------+         +------------+------------+         +------------+
+        // remote ip              public ip                           private ip
+        // 8.8.8.8:443            <Upstream ip>:9876                  <TetheredDevice ip>:9876
+        //
         final TetheringTester tester = initTetheringTester(toList(TEST_IP4_ADDR),
                 toList(TEST_IP4_DNS));
         final TetheredDevice tethered = tester.createTetheredDevice(TEST_MAC, false /* hasIpv6 */);
@@ -541,15 +524,6 @@
         sendDownloadPacketUdp(remoteIp, tetheringUpstreamIp, tester, false /* is6To4 */);
     }
 
-    /**
-     * Basic IPv4 UDP tethering test. Verify that UDP tethered packets are transferred no matter
-     * using which data path.
-     */
-    @Test
-    public void testTetherUdpV4() throws Exception {
-        runUdp4Test();
-    }
-
     // Test network topology:
     //
     //            public network (rawip)                 private network
@@ -599,7 +573,7 @@
         final TetheredDevice tethered = tester.createTetheredDevice(TEST_MAC, false /* hasIpv6 */);
 
         // TODO: remove the connectivity verification for upstream connected notification race.
-        // See the same reason in runUdp4Test().
+        // See the same reason in testTetherUdp4().
         probeV4TetheringConnectivity(tester, tethered, false /* is4To6 */);
 
         final ByteBuffer request = buildIcmpEchoPacketV4(tethered.macAddr /* srcMac */,
@@ -707,7 +681,7 @@
         final TetheredDevice tethered = tester.createTetheredDevice(TEST_MAC, false /* hasIpv6 */);
 
         // TODO: remove the connectivity verification for upstream connected notification race.
-        // See the same reason in runUdp4Test().
+        // See the same reason in testTetherUdp4().
         probeV4TetheringConnectivity(tester, tethered, false /* is4To6 */);
 
         // [1] Send DNS query.
@@ -751,7 +725,7 @@
         final TetheredDevice tethered = tester.createTetheredDevice(TEST_MAC, false /* hasIpv6 */);
 
         // TODO: remove the connectivity verification for upstream connected notification race.
-        // See the same reason in runUdp4Test().
+        // See the same reason in testTetherUdp4().
         probeV4TetheringConnectivity(tester, tethered, false /* is4To6 */);
 
         runTcpTest(tethered.macAddr /* uploadSrcMac */, tethered.routerMacAddr /* uploadDstMac */,
diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java
index 5323392..114cf2e 100644
--- a/service-t/src/com/android/server/net/NetworkStatsService.java
+++ b/service-t/src/com/android/server/net/NetworkStatsService.java
@@ -1544,7 +1544,11 @@
     }
 
     @Override
-    public INetworkStatsSession openSessionForUsageStats(int flags, String callingPackage) {
+    public INetworkStatsSession openSessionForUsageStats(
+            int flags, @NonNull String callingPackage) {
+        Objects.requireNonNull(callingPackage);
+        PermissionUtils.enforcePackageNameMatchesUid(
+                mContext, Binder.getCallingUid(), callingPackage);
         return openSessionInternal(flags, callingPackage);
     }
 
@@ -2061,6 +2065,7 @@
 
         final int callingPid = Binder.getCallingPid();
         final int callingUid = Binder.getCallingUid();
+        PermissionUtils.enforcePackageNameMatchesUid(mContext, callingUid, callingPackage);
         @NetworkStatsAccess.Level int accessLevel = checkAccessLevel(callingPackage);
         DataUsageRequest normalizedRequest;
         final long token = Binder.clearCallingIdentity();
diff --git a/service/ServiceConnectivityResources/res/values-de/strings.xml b/service/ServiceConnectivityResources/res/values-de/strings.xml
index 536ebda..f58efb0 100644
--- a/service/ServiceConnectivityResources/res/values-de/strings.xml
+++ b/service/ServiceConnectivityResources/res/values-de/strings.xml
@@ -29,7 +29,7 @@
     <string name="wifi_no_internet_detailed" msgid="1746921096565304090">"Für Optionen tippen"</string>
     <string name="mobile_no_internet" msgid="4087718456753201450">"Mobiles Netzwerk hat keinen Internetzugriff"</string>
     <string name="other_networks_no_internet" msgid="5693932964749676542">"Netzwerk hat keinen Internetzugriff"</string>
-    <string name="private_dns_broken_detailed" msgid="2677123850463207823">"Auf den privaten DNS-Server kann nicht zugegriffen werden"</string>
+    <string name="private_dns_broken_detailed" msgid="2677123850463207823">"Auf den Server des privaten DNS kann nicht zugegriffen werden"</string>
     <string name="network_partial_connectivity" msgid="5549503845834993258">"Schlechte Verbindung mit <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="network_partial_connectivity_detailed" msgid="4732435946300249845">"Tippen, um die Verbindung trotzdem herzustellen"</string>
     <string name="network_switch_metered" msgid="5016937523571166319">"Zu <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> gewechselt"</string>
diff --git a/tests/cts/net/src/android/net/cts/NsdManagerDownstreamTetheringTest.kt b/tests/cts/net/src/android/net/cts/NsdManagerDownstreamTetheringTest.kt
index 1b1f367..a3c3f45 100644
--- a/tests/cts/net/src/android/net/cts/NsdManagerDownstreamTetheringTest.kt
+++ b/tests/cts/net/src/android/net/cts/NsdManagerDownstreamTetheringTest.kt
@@ -72,7 +72,7 @@
 
         tryTest {
             downstreamIface = createTestInterface()
-            val iface = tetheredInterface
+            val iface = mTetheredInterfaceRequester.getInterface()
             assertEquals(iface, downstreamIface?.interfaceName)
             val request = TetheringRequest.Builder(TETHERING_ETHERNET)
                 .setConnectivityScope(CONNECTIVITY_SCOPE_LOCAL).build()
@@ -115,7 +115,7 @@
 
         tryTest {
             downstreamIface = createTestInterface()
-            val iface = tetheredInterface
+            val iface = mTetheredInterfaceRequester.getInterface()
             assertEquals(iface, downstreamIface?.interfaceName)
 
             val localAddr = LinkAddress("192.0.2.3/28")
diff --git a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
index c997b01..7e0a225 100644
--- a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -65,6 +65,7 @@
 import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
 import static android.text.format.DateUtils.WEEK_IN_MILLIS;
 
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doThrow;
 import static com.android.server.net.NetworkStatsEventLogger.POLL_REASON_RAT_CHANGED;
 import static com.android.server.net.NetworkStatsEventLogger.PollEvent.pollReasonNameOf;
 import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_POLL;
@@ -102,6 +103,7 @@
 import android.app.AlarmManager;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.database.ContentObserver;
 import android.net.DataUsageRequest;
@@ -132,6 +134,7 @@
 import android.os.PowerManager;
 import android.os.Process;
 import android.os.SimpleClock;
+import android.os.UserHandle;
 import android.provider.Settings;
 import android.system.ErrnoException;
 import android.telephony.TelephonyManager;
@@ -256,6 +259,7 @@
     private static @Mock WifiInfo sWifiInfo;
     private @Mock INetd mNetd;
     private @Mock TetheringManager mTetheringManager;
+    private @Mock PackageManager mPm;
     private @Mock NetworkStatsFactory mStatsFactory;
     @NonNull
     private final TestNetworkStatsSettings mSettings =
@@ -327,6 +331,16 @@
         }
 
         @Override
+        public PackageManager getPackageManager() {
+            return mPm;
+        }
+
+        @Override
+        public Context createContextAsUser(UserHandle user, int flags) {
+            return this;
+        }
+
+        @Override
         public Object getSystemService(String name) {
             if (Context.TELEPHONY_SERVICE.equals(name)) return mTelephonyManager;
             if (Context.TETHERING_SERVICE.equals(name)) return mTetheringManager;
@@ -447,6 +461,9 @@
                 any(), tetheringEventCbCaptor.capture());
         mTetheringEventCallback = tetheringEventCbCaptor.getValue();
 
+        doReturn(Process.myUid()).when(mPm)
+                .getPackageUid(eq(mServiceContext.getPackageName()), anyInt());
+
         mUsageCallback = new TestableUsageCallback(mUsageCallbackBinder);
     }
 
@@ -1714,7 +1731,7 @@
 
         // Register and verify request and that binder was called
         DataUsageRequest request = mService.registerUsageCallback(
-                mServiceContext.getOpPackageName(), inputRequest, mUsageCallback);
+                mServiceContext.getPackageName(), inputRequest, mUsageCallback);
         assertTrue(request.requestId > 0);
         assertTrue(Objects.equals(sTemplateWifi, request.template));
         long minThresholdInBytes = 2 * 1024 * 1024; // 2 MB
@@ -3005,6 +3022,38 @@
     }
 
     @Test
+    public void testEnforcePackageNameMatchesUid() throws Exception {
+        final String testMyPackageName = "test.package.myname";
+        final String testRedPackageName = "test.package.red";
+        final String testInvalidPackageName = "test.package.notfound";
+
+        doReturn(UID_RED).when(mPm).getPackageUid(eq(testRedPackageName), anyInt());
+        doReturn(Process.myUid()).when(mPm).getPackageUid(eq(testMyPackageName), anyInt());
+        doThrow(new PackageManager.NameNotFoundException()).when(mPm)
+                .getPackageUid(eq(testInvalidPackageName), anyInt());
+
+        assertThrows(SecurityException.class, () ->
+                mService.openSessionForUsageStats(0 /* flags */, testRedPackageName));
+        assertThrows(SecurityException.class, () ->
+                mService.openSessionForUsageStats(0 /* flags */, testInvalidPackageName));
+        assertThrows(NullPointerException.class, () ->
+                mService.openSessionForUsageStats(0 /* flags */, null));
+        // Verify package name belongs to ourselves does not throw.
+        mService.openSessionForUsageStats(0 /* flags */, testMyPackageName);
+
+        long thresholdInBytes = 10 * 1024 * 1024;  // 10 MB
+        DataUsageRequest request = new DataUsageRequest(
+                2 /* requestId */, sTemplateImsi1, thresholdInBytes);
+        assertThrows(SecurityException.class, () ->
+                mService.registerUsageCallback(testRedPackageName, request, mUsageCallback));
+        assertThrows(SecurityException.class, () ->
+                mService.registerUsageCallback(testInvalidPackageName, request, mUsageCallback));
+        assertThrows(NullPointerException.class, () ->
+                mService.registerUsageCallback(null, request, mUsageCallback));
+        mService.registerUsageCallback(testMyPackageName, request, mUsageCallback);
+    }
+
+    @Test
     public void testDumpSkDestroyListenerLogs() throws ErrnoException {
         doAnswer((invocation) -> {
             final IndentingPrintWriter ipw = (IndentingPrintWriter) invocation.getArgument(0);
diff --git a/thread/service/java/com/android/server/thread/InfraInterfaceController.java b/thread/service/java/com/android/server/thread/InfraInterfaceController.java
index be54cbc..e72c9ee 100644
--- a/thread/service/java/com/android/server/thread/InfraInterfaceController.java
+++ b/thread/service/java/com/android/server/thread/InfraInterfaceController.java
@@ -16,14 +16,30 @@
 
 package com.android.server.thread;
 
-import android.os.ParcelFileDescriptor;
+import static android.system.OsConstants.IPPROTO_IPV6;
+import static android.system.OsConstants.IPPROTO_RAW;
+import static android.system.OsConstants.IPV6_CHECKSUM;
+import static android.system.OsConstants.IPV6_MULTICAST_HOPS;
+import static android.system.OsConstants.IPV6_RECVHOPLIMIT;
+import static android.system.OsConstants.IPV6_RECVPKTINFO;
+import static android.system.OsConstants.IPV6_UNICAST_HOPS;
 
+import android.net.util.SocketUtils;
+import android.os.ParcelFileDescriptor;
+import android.system.ErrnoException;
+import android.system.Os;
+
+import java.io.FileDescriptor;
 import java.io.IOException;
 
 /** Controller for the infrastructure network interface. */
 public class InfraInterfaceController {
     private static final String TAG = "InfraIfController";
 
+    private static final int ENABLE = 1;
+    private static final int IPV6_CHECKSUM_OFFSET = 2;
+    private static final int HOP_LIMIT = 255;
+
     static {
         System.loadLibrary("service-thread-jni");
     }
@@ -37,8 +53,21 @@
      * @throws IOException when fails to create the socket.
      */
     public ParcelFileDescriptor createIcmp6Socket(String infraInterfaceName) throws IOException {
-        return ParcelFileDescriptor.adoptFd(nativeCreateIcmp6Socket(infraInterfaceName));
+        ParcelFileDescriptor parcelFd =
+                ParcelFileDescriptor.adoptFd(nativeCreateFilteredIcmp6Socket());
+        FileDescriptor fd = parcelFd.getFileDescriptor();
+        try {
+            Os.setsockoptInt(fd, IPPROTO_RAW, IPV6_CHECKSUM, IPV6_CHECKSUM_OFFSET);
+            Os.setsockoptInt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, ENABLE);
+            Os.setsockoptInt(fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, ENABLE);
+            Os.setsockoptInt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, HOP_LIMIT);
+            Os.setsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, HOP_LIMIT);
+            SocketUtils.bindSocketToInterface(fd, infraInterfaceName);
+        } catch (ErrnoException e) {
+            throw new IOException("Failed to setsockopt for the ICMPv6 socket", e);
+        }
+        return parcelFd;
     }
 
-    private static native int nativeCreateIcmp6Socket(String interfaceName) throws IOException;
+    private static native int nativeCreateFilteredIcmp6Socket() throws IOException;
 }
diff --git a/thread/service/jni/com_android_server_thread_InfraInterfaceController.cpp b/thread/service/jni/com_android_server_thread_InfraInterfaceController.cpp
index 5d24eab..1f260f2 100644
--- a/thread/service/jni/com_android_server_thread_InfraInterfaceController.cpp
+++ b/thread/service/jni/com_android_server_thread_InfraInterfaceController.cpp
@@ -42,15 +42,8 @@
 
 namespace android {
 static jint
-com_android_server_thread_InfraInterfaceController_createIcmp6Socket(JNIEnv *env, jobject clazz,
-                                                                     jstring interfaceName) {
-  ScopedUtfChars ifName(env, interfaceName);
-
-  struct icmp6_filter filter;
-  constexpr int kEnable = 1;
-  constexpr int kIpv6ChecksumOffset = 2;
-  constexpr int kHopLimit = 255;
-
+com_android_server_thread_InfraInterfaceController_createFilteredIcmp6Socket(JNIEnv *env,
+                                                                             jobject clazz) {
   // Initializes the ICMPv6 socket.
   int sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
   if (sock == -1) {
@@ -59,6 +52,7 @@
     return -1;
   }
 
+  struct icmp6_filter filter;
   // Only accept Router Advertisements, Router Solicitations and Neighbor
   // Advertisements.
   ICMP6_FILTER_SETBLOCKALL(&filter);
@@ -73,53 +67,6 @@
     return -1;
   }
 
-  // We want a source address and interface index.
-
-  if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &kEnable, sizeof(kEnable)) != 0) {
-    jniThrowExceptionFmt(env, "java/io/IOException", "failed to setsockopt IPV6_RECVPKTINFO (%s)",
-                         strerror(errno));
-    close(sock);
-    return -1;
-  }
-
-  if (setsockopt(sock, IPPROTO_RAW, IPV6_CHECKSUM, &kIpv6ChecksumOffset,
-                 sizeof(kIpv6ChecksumOffset)) != 0) {
-    jniThrowExceptionFmt(env, "java/io/IOException", "failed to setsockopt IPV6_CHECKSUM (%s)",
-                         strerror(errno));
-    close(sock);
-    return -1;
-  }
-
-  // We need to be able to reject RAs arriving from off-link.
-  if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &kEnable, sizeof(kEnable)) != 0) {
-    jniThrowExceptionFmt(env, "java/io/IOException", "failed to setsockopt IPV6_RECVHOPLIMIT (%s)",
-                         strerror(errno));
-    close(sock);
-    return -1;
-  }
-
-  if (setsockopt(sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &kHopLimit, sizeof(kHopLimit)) != 0) {
-    jniThrowExceptionFmt(env, "java/io/IOException", "failed to setsockopt IPV6_UNICAST_HOPS (%s)",
-                         strerror(errno));
-    close(sock);
-    return -1;
-  }
-
-  if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &kHopLimit, sizeof(kHopLimit)) != 0) {
-    jniThrowExceptionFmt(env, "java/io/IOException",
-                         "failed to create the setsockopt IPV6_MULTICAST_HOPS (%s)",
-                         strerror(errno));
-    close(sock);
-    return -1;
-  }
-
-  if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, ifName.c_str(), strlen(ifName.c_str()))) {
-    jniThrowExceptionFmt(env, "java/io/IOException", "failed to setsockopt SO_BINDTODEVICE (%s)",
-                         strerror(errno));
-    close(sock);
-    return -1;
-  }
-
   return sock;
 }
 
@@ -129,8 +76,8 @@
 
 static const JNINativeMethod gMethods[] = {
     /* name, signature, funcPtr */
-    {"nativeCreateIcmp6Socket", "(Ljava/lang/String;)I",
-     (void *)com_android_server_thread_InfraInterfaceController_createIcmp6Socket},
+    {"nativeCreateFilteredIcmp6Socket", "()I",
+     (void *)com_android_server_thread_InfraInterfaceController_createFilteredIcmp6Socket},
 };
 
 int register_com_android_server_thread_InfraInterfaceController(JNIEnv *env) {
diff --git a/thread/tests/cts/Android.bp b/thread/tests/cts/Android.bp
index 8cdf38d..c1cf0a0 100644
--- a/thread/tests/cts/Android.bp
+++ b/thread/tests/cts/Android.bp
@@ -21,6 +21,7 @@
 
 android_test {
     name: "CtsThreadNetworkTestCases",
+    defaults: ["cts_defaults"],
     min_sdk_version: "33",
     sdk_version: "test_current",
     manifest: "AndroidManifest.xml",