Merge "Expose additional Cronet APIs in AOSP."
diff --git a/Cronet/tests/common/Android.bp b/Cronet/tests/common/Android.bp
index 1ed0881..f8bdb08 100644
--- a/Cronet/tests/common/Android.bp
+++ b/Cronet/tests/common/Android.bp
@@ -35,5 +35,5 @@
"NetHttpTestsLibPreJarJar",
],
jarjar_rules: ":framework-tethering-jarjar-rules",
- compile_multilib: "both",
+ compile_multilib: "both", // Include both the 32 and 64 bit versions
}
diff --git a/Cronet/tests/cts/Android.bp b/Cronet/tests/cts/Android.bp
index 9a5ed89..d260694 100644
--- a/Cronet/tests/cts/Android.bp
+++ b/Cronet/tests/cts/Android.bp
@@ -49,12 +49,14 @@
"src/**/*.kt",
],
static_libs: [
+ "androidx.test.ext.junit",
"androidx.test.rules",
"androidx.core_core",
"ctstestrunner-axt",
"ctstestserver",
"junit",
"hamcrest-library",
+ "kotlin-test",
],
libs: [
"android.test.runner",
@@ -73,7 +75,6 @@
"CronetTestJavaDefaults",
],
sdk_version: "test_current",
- compile_multilib: "both", // Include both the 32 and 64 bit versions
static_libs: ["CtsNetHttpTestsLib"],
// Tag this as a cts test artifact
test_suites: [
diff --git a/Cronet/tests/cts/src/android/net/http/cts/CallbackExceptionTest.kt b/Cronet/tests/cts/src/android/net/http/cts/CallbackExceptionTest.kt
new file mode 100644
index 0000000..e17b63f
--- /dev/null
+++ b/Cronet/tests/cts/src/android/net/http/cts/CallbackExceptionTest.kt
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.http.cts
+
+import android.content.Context
+import android.net.http.CallbackException
+import android.net.http.HttpEngine
+import android.net.http.cts.util.HttpCtsTestServer
+import android.net.http.cts.util.TestUrlRequestCallback
+import android.net.http.cts.util.TestUrlRequestCallback.FailureType
+import android.net.http.cts.util.TestUrlRequestCallback.ResponseStep
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import kotlin.test.Test
+import kotlin.test.assertEquals
+import kotlin.test.assertIs
+import kotlin.test.assertSame
+import kotlin.test.assertTrue
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class CallbackExceptionTest {
+
+ @Test
+ fun testCallbackException_returnsInputParameters() {
+ val message = "failed"
+ val cause = Throwable("exception")
+ val callbackException = object : CallbackException(message, cause) {}
+
+ assertEquals(message, callbackException.message)
+ assertSame(cause, callbackException.cause)
+ }
+
+ @Test
+ fun testCallbackException_thrownFromUrlRequest() {
+ val context: Context = ApplicationProvider.getApplicationContext()
+ val server = HttpCtsTestServer(context)
+ val httpEngine = HttpEngine.Builder(context).build()
+ val callback = TestUrlRequestCallback()
+ callback.setFailure(FailureType.THROW_SYNC, ResponseStep.ON_RESPONSE_STARTED)
+ val request = httpEngine
+ .newUrlRequestBuilder(server.successUrl, callback, callback.executor)
+ .build()
+
+ request.start()
+ callback.blockForDone()
+
+ assertTrue(request.isDone)
+ assertIs<CallbackException>(callback.mError)
+ server.shutdown()
+ httpEngine.shutdown()
+ }
+}
diff --git a/Cronet/tests/cts/src/android/net/http/cts/NetworkExceptionTest.kt b/Cronet/tests/cts/src/android/net/http/cts/NetworkExceptionTest.kt
new file mode 100644
index 0000000..a2611e4
--- /dev/null
+++ b/Cronet/tests/cts/src/android/net/http/cts/NetworkExceptionTest.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.http.cts
+
+import android.net.http.HttpEngine
+import android.net.http.NetworkException
+import android.net.http.cts.util.TestUrlRequestCallback
+import androidx.test.core.app.ApplicationProvider
+import kotlin.test.assertEquals
+import kotlin.test.assertIs
+import kotlin.test.assertSame
+import kotlin.test.assertTrue
+import org.junit.Test
+
+class NetworkExceptionTest {
+
+ @Test
+ fun testNetworkException_returnsInputParameters() {
+ val message = "failed"
+ val cause = Throwable("thrown")
+ val networkException =
+ object : NetworkException(message, cause) {
+ override fun getErrorCode() = 0
+ override fun isImmediatelyRetryable() = false
+ }
+
+ assertEquals(message, networkException.message)
+ assertSame(cause, networkException.cause)
+ }
+
+ @Test
+ fun testNetworkException_thrownFromUrlRequest() {
+ val httpEngine = HttpEngine.Builder(ApplicationProvider.getApplicationContext()).build()
+ val callback = TestUrlRequestCallback()
+ val request =
+ httpEngine.newUrlRequestBuilder("http://localhost", callback, callback.executor).build()
+
+ request.start()
+ callback.blockForDone()
+
+ assertTrue(request.isDone)
+ assertIs<NetworkException>(callback.mError)
+ httpEngine.shutdown()
+ }
+}
diff --git a/Cronet/tests/mts/Android.bp b/Cronet/tests/mts/Android.bp
index cfafc5b..1cabd63 100644
--- a/Cronet/tests/mts/Android.bp
+++ b/Cronet/tests/mts/Android.bp
@@ -37,7 +37,6 @@
"CronetTestJavaDefaults",
"mts-target-sdk-version-current",
],
- compile_multilib: "both",
sdk_version: "test_current",
static_libs: ["NetHttpTestsLibPreJarJar"],
jarjar_rules: ":framework-tethering-jarjar-rules",
diff --git a/Tethering/common/TetheringLib/cronet_enabled/api/current.txt b/Tethering/common/TetheringLib/cronet_enabled/api/current.txt
index bff5cf5..0ed1e9f 100644
--- a/Tethering/common/TetheringLib/cronet_enabled/api/current.txt
+++ b/Tethering/common/TetheringLib/cronet_enabled/api/current.txt
@@ -92,6 +92,7 @@
}
public abstract class HttpEngine {
+ method public void bindToNetwork(@Nullable android.net.Network);
method public abstract java.net.URLStreamHandlerFactory createURLStreamHandlerFactory();
method public static String getVersionString();
method public abstract android.net.http.BidirectionalStream.Builder newBidirectionalStreamBuilder(String, android.net.http.BidirectionalStream.Callback, java.util.concurrent.Executor);
@@ -194,6 +195,7 @@
public abstract static class UrlRequest.Builder {
method public abstract android.net.http.UrlRequest.Builder addHeader(String, String);
method public abstract android.net.http.UrlRequest.Builder allowDirectExecutor();
+ method public abstract android.net.http.UrlRequest.Builder bindToNetwork(@Nullable android.net.Network);
method public abstract android.net.http.UrlRequest build();
method public abstract android.net.http.UrlRequest.Builder disableCache();
method public abstract android.net.http.UrlRequest.Builder setHttpMethod(String);
diff --git a/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java b/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java
index c452e55..775c36f 100644
--- a/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java
+++ b/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java
@@ -88,13 +88,13 @@
private static final int MIN_RTR_ADV_INTERVAL_SEC = 300;
private static final int MAX_RTR_ADV_INTERVAL_SEC = 600;
// In general, router, prefix, and DNS lifetimes are all advised to be
- // greater than or equal to 3 * MAX_RTR_ADV_INTERVAL. Here, we double
+ // greater than or equal to 3 * MAX_RTR_ADV_INTERVAL. Here, we quadruple
// that to allow for multicast packet loss.
//
// This MAX_RTR_ADV_INTERVAL_SEC and DEFAULT_LIFETIME are also consistent
// with the https://tools.ietf.org/html/rfc7772#section-4 discussion of
// "approximately 7 RAs per hour".
- private static final int DEFAULT_LIFETIME = 6 * MAX_RTR_ADV_INTERVAL_SEC;
+ private static final int DEFAULT_LIFETIME = 12 * MAX_RTR_ADV_INTERVAL_SEC;
// From https://tools.ietf.org/html/rfc4861#section-10 .
private static final int MIN_DELAY_BETWEEN_RAS_SEC = 3;
// Both initial and final RAs, but also for changes in RA contents.
diff --git a/Tethering/tests/integration/Android.bp b/Tethering/tests/integration/Android.bp
index 11e3dc0..5e08aba 100644
--- a/Tethering/tests/integration/Android.bp
+++ b/Tethering/tests/integration/Android.bp
@@ -21,8 +21,7 @@
name: "TetheringIntegrationTestsDefaults",
defaults: ["framework-connectivity-test-defaults"],
srcs: [
- "src/**/*.java",
- "src/**/*.kt",
+ "base/**/*.java",
],
min_sdk_version: "30",
static_libs: [
@@ -47,6 +46,16 @@
],
}
+android_library {
+ name: "TetheringIntegrationTestsBaseLib",
+ target_sdk_version: "current",
+ platform_apis: true,
+ defaults: ["TetheringIntegrationTestsDefaults"],
+ visibility: [
+ "//packages/modules/Connectivity/Tethering/tests/mts",
+ ]
+}
+
// Library including tethering integration tests targeting the latest stable SDK.
// Use with NetworkStackJarJarRules.
android_library {
@@ -54,6 +63,9 @@
target_sdk_version: "33",
platform_apis: true,
defaults: ["TetheringIntegrationTestsDefaults"],
+ srcs: [
+ "src/**/*.java",
+ ],
visibility: [
"//packages/modules/Connectivity/tests/cts/tethering",
"//packages/modules/Connectivity/tests:__subpackages__",
@@ -68,12 +80,16 @@
target_sdk_version: "current",
platform_apis: true,
defaults: ["TetheringIntegrationTestsDefaults"],
+ srcs: [
+ "src/**/*.java",
+ ],
visibility: [
"//packages/modules/Connectivity/tests/cts/tethering",
"//packages/modules/Connectivity/Tethering/tests/mts",
]
}
+// TODO: remove because TetheringIntegrationTests has been covered by ConnectivityCoverageTests.
android_test {
name: "TetheringIntegrationTests",
platform_apis: true,
@@ -81,6 +97,9 @@
test_suites: [
"device-tests",
],
+ srcs: [
+ "src/**/*.java",
+ ],
compile_multilib: "both",
jarjar_rules: ":NetworkStackJarJarRules",
}
diff --git a/Tethering/tests/integration/src/android/net/EthernetTetheringTestBase.java b/Tethering/tests/integration/base/android/net/EthernetTetheringTestBase.java
similarity index 100%
rename from Tethering/tests/integration/src/android/net/EthernetTetheringTestBase.java
rename to Tethering/tests/integration/base/android/net/EthernetTetheringTestBase.java
diff --git a/Tethering/tests/integration/src/android/net/TetheringTester.java b/Tethering/tests/integration/base/android/net/TetheringTester.java
similarity index 100%
rename from Tethering/tests/integration/src/android/net/TetheringTester.java
rename to Tethering/tests/integration/base/android/net/TetheringTester.java
diff --git a/Tethering/tests/integration/src/android/net/CtsEthernetTetheringTest.java b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
similarity index 78%
rename from Tethering/tests/integration/src/android/net/CtsEthernetTetheringTest.java
rename to Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
index aea6728..fb4b9fa 100644
--- a/Tethering/tests/integration/src/android/net/CtsEthernetTetheringTest.java
+++ b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
@@ -16,7 +16,6 @@
package android.net;
-import static android.Manifest.permission.DUMP;
import static android.net.InetAddresses.parseNumericAddress;
import static android.net.TetheringManager.CONNECTIVITY_SCOPE_LOCAL;
import static android.net.TetheringManager.TETHERING_ETHERNET;
@@ -26,7 +25,6 @@
import static android.system.OsConstants.ICMP_ECHO;
import static android.system.OsConstants.ICMP_ECHOREPLY;
import static android.system.OsConstants.IPPROTO_ICMP;
-import static android.system.OsConstants.IPPROTO_UDP;
import static com.android.net.module.util.ConnectivityUtils.isIPv6ULA;
import static com.android.net.module.util.HexDump.dumpHexString;
@@ -39,39 +37,28 @@
import static com.android.net.module.util.NetworkStackConstants.IPV4_CHECKSUM_OFFSET;
import static com.android.net.module.util.NetworkStackConstants.IPV4_HEADER_MIN_LEN;
import static com.android.net.module.util.NetworkStackConstants.IPV4_LENGTH_OFFSET;
-import static com.android.testutils.DeviceInfoUtils.KVersion;
-import static com.android.testutils.TestPermissionUtil.runAsShell;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
-import android.content.Context;
import android.net.TetheringManager.TetheringRequest;
import android.net.TetheringTester.TetheredDevice;
import android.os.Build;
import android.os.SystemClock;
import android.os.SystemProperties;
-import android.os.VintfRuntimeInfo;
import android.util.Log;
-import android.util.Pair;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.test.filters.MediumTest;
import androidx.test.runner.AndroidJUnit4;
-import com.android.net.module.util.BpfDump;
import com.android.net.module.util.Ipv6Utils;
import com.android.net.module.util.Struct;
-import com.android.net.module.util.bpf.Tether4Key;
-import com.android.net.module.util.bpf.Tether4Value;
-import com.android.net.module.util.bpf.TetherStatsKey;
-import com.android.net.module.util.bpf.TetherStatsValue;
import com.android.net.module.util.structs.EthernetHeader;
import com.android.net.module.util.structs.Icmpv4Header;
import com.android.net.module.util.structs.Ipv4Header;
@@ -79,8 +66,6 @@
import com.android.net.module.util.structs.UdpHeader;
import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
-import com.android.testutils.DeviceInfoUtils;
-import com.android.testutils.DumpTestUtils;
import com.android.testutils.TapPacketReader;
import org.junit.Rule;
@@ -96,9 +81,7 @@
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Collection;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
@@ -106,34 +89,13 @@
@RunWith(AndroidJUnit4.class)
@MediumTest
-public class CtsEthernetTetheringTest extends EthernetTetheringTestBase {
+public class EthernetTetheringTest extends EthernetTetheringTestBase {
@Rule
public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule();
- private static final String TAG = CtsEthernetTetheringTest.class.getSimpleName();
-
- private static final int DUMP_POLLING_MAX_RETRY = 100;
- private static final int DUMP_POLLING_INTERVAL_MS = 50;
- // Kernel treats a confirmed UDP connection which active after two seconds as stream mode.
- // See upstream commit b7b1d02fc43925a4d569ec221715db2dfa1ce4f5.
- private static final int UDP_STREAM_TS_MS = 2000;
- // Give slack time for waiting UDP stream mode because handling conntrack event in user space
- // may not in precise time. Used to reduce the flaky rate.
- private static final int UDP_STREAM_SLACK_MS = 500;
- // Per RX UDP packet size: iphdr (20) + udphdr (8) + payload (2) = 30 bytes.
- private static final int RX_UDP_PACKET_SIZE = 30;
- private static final int RX_UDP_PACKET_COUNT = 456;
- // Per TX UDP packet size: ethhdr (14) + iphdr (20) + udphdr (8) + payload (2) = 44 bytes.
- private static final int TX_UDP_PACKET_SIZE = 44;
- private static final int TX_UDP_PACKET_COUNT = 123;
+ private static final String TAG = EthernetTetheringTest.class.getSimpleName();
private static final short DNS_PORT = 53;
-
- private static final String DUMPSYS_TETHERING_RAWMAP_ARG = "bpfRawMap";
- private static final String DUMPSYS_RAWMAP_ARG_STATS = "--stats";
- private static final String DUMPSYS_RAWMAP_ARG_UPSTREAM4 = "--upstream4";
- private static final String LINE_DELIMITER = "\\n";
-
private static final short ICMPECHO_CODE = 0x0;
private static final short ICMPECHO_ID = 0x0;
private static final short ICMPECHO_SEQ = 0x0;
@@ -529,7 +491,7 @@
// remote ip public ip private ip
// 8.8.8.8:443 <Upstream ip>:9876 <TetheredDevice ip>:9876
//
- private void runUdp4Test(boolean verifyBpf) throws Exception {
+ private void runUdp4Test() throws Exception {
final TetheringTester tester = initTetheringTester(toList(TEST_IP4_ADDR),
toList(TEST_IP4_DNS));
final TetheredDevice tethered = tester.createTetheredDevice(TEST_MAC, false /* hasIpv6 */);
@@ -549,123 +511,6 @@
final InetAddress clientIp = tethered.ipv4Addr;
sendUploadPacketUdp(srcMac, dstMac, clientIp, remoteIp, tester, false /* is4To6 */);
sendDownloadPacketUdp(remoteIp, tetheringUpstreamIp, tester, false /* is6To4 */);
-
- if (verifyBpf) {
- // Send second UDP packet in original direction.
- // The BPF coordinator only offloads the ASSURED conntrack entry. The "request + reply"
- // packets can make status IPS_SEEN_REPLY to be set. Need one more packet to make
- // conntrack status IPS_ASSURED_BIT to be set. Note the third packet needs to delay
- // 2 seconds because kernel monitors a UDP connection which still alive after 2 seconds
- // and apply ASSURED flag.
- // See kernel upstream commit b7b1d02fc43925a4d569ec221715db2dfa1ce4f5 and
- // nf_conntrack_udp_packet in net/netfilter/nf_conntrack_proto_udp.c
- Thread.sleep(UDP_STREAM_TS_MS);
- sendUploadPacketUdp(srcMac, dstMac, clientIp, remoteIp, tester, false /* is4To6 */);
-
- // Give a slack time for handling conntrack event in user space.
- Thread.sleep(UDP_STREAM_SLACK_MS);
-
- // [1] Verify IPv4 upstream rule map.
- final HashMap<Tether4Key, Tether4Value> upstreamMap = pollRawMapFromDump(
- Tether4Key.class, Tether4Value.class, DUMPSYS_RAWMAP_ARG_UPSTREAM4);
- assertNotNull(upstreamMap);
- assertEquals(1, upstreamMap.size());
-
- final Map.Entry<Tether4Key, Tether4Value> rule =
- upstreamMap.entrySet().iterator().next();
-
- final Tether4Key upstream4Key = rule.getKey();
- assertEquals(IPPROTO_UDP, upstream4Key.l4proto);
- assertTrue(Arrays.equals(tethered.ipv4Addr.getAddress(), upstream4Key.src4));
- assertEquals(LOCAL_PORT, upstream4Key.srcPort);
- assertTrue(Arrays.equals(REMOTE_IP4_ADDR.getAddress(), upstream4Key.dst4));
- assertEquals(REMOTE_PORT, upstream4Key.dstPort);
-
- final Tether4Value upstream4Value = rule.getValue();
- assertTrue(Arrays.equals(tetheringUpstreamIp.getAddress(),
- InetAddress.getByAddress(upstream4Value.src46).getAddress()));
- assertEquals(LOCAL_PORT, upstream4Value.srcPort);
- assertTrue(Arrays.equals(REMOTE_IP4_ADDR.getAddress(),
- InetAddress.getByAddress(upstream4Value.dst46).getAddress()));
- assertEquals(REMOTE_PORT, upstream4Value.dstPort);
-
- // [2] Verify stats map.
- // Transmit packets on both direction for verifying stats. Because we only care the
- // packet count in stats test, we just reuse the existing packets to increaes
- // the packet count on both direction.
-
- // Send packets on original direction.
- for (int i = 0; i < TX_UDP_PACKET_COUNT; i++) {
- sendUploadPacketUdp(srcMac, dstMac, clientIp, remoteIp, tester,
- false /* is4To6 */);
- }
-
- // Send packets on reply direction.
- for (int i = 0; i < RX_UDP_PACKET_COUNT; i++) {
- sendDownloadPacketUdp(remoteIp, tetheringUpstreamIp, tester, false /* is6To4 */);
- }
-
- // Dump stats map to verify.
- final HashMap<TetherStatsKey, TetherStatsValue> statsMap = pollRawMapFromDump(
- TetherStatsKey.class, TetherStatsValue.class, DUMPSYS_RAWMAP_ARG_STATS);
- assertNotNull(statsMap);
- assertEquals(1, statsMap.size());
-
- final Map.Entry<TetherStatsKey, TetherStatsValue> stats =
- statsMap.entrySet().iterator().next();
-
- // TODO: verify the upstream index in TetherStatsKey.
-
- final TetherStatsValue statsValue = stats.getValue();
- assertEquals(RX_UDP_PACKET_COUNT, statsValue.rxPackets);
- assertEquals(RX_UDP_PACKET_COUNT * RX_UDP_PACKET_SIZE, statsValue.rxBytes);
- assertEquals(0, statsValue.rxErrors);
- assertEquals(TX_UDP_PACKET_COUNT, statsValue.txPackets);
- assertEquals(TX_UDP_PACKET_COUNT * TX_UDP_PACKET_SIZE, statsValue.txBytes);
- assertEquals(0, statsValue.txErrors);
- }
- }
-
- private static boolean isUdpOffloadSupportedByKernel(final String kernelVersion) {
- final KVersion current = DeviceInfoUtils.getMajorMinorSubminorVersion(kernelVersion);
- return current.isInRange(new KVersion(4, 14, 222), new KVersion(4, 19, 0))
- || current.isInRange(new KVersion(4, 19, 176), new KVersion(5, 4, 0))
- || current.isAtLeast(new KVersion(5, 4, 98));
- }
-
- @Test
- public void testIsUdpOffloadSupportedByKernel() throws Exception {
- assertFalse(isUdpOffloadSupportedByKernel("4.14.221"));
- assertTrue(isUdpOffloadSupportedByKernel("4.14.222"));
- assertTrue(isUdpOffloadSupportedByKernel("4.16.0"));
- assertTrue(isUdpOffloadSupportedByKernel("4.18.0"));
- assertFalse(isUdpOffloadSupportedByKernel("4.19.0"));
-
- assertFalse(isUdpOffloadSupportedByKernel("4.19.175"));
- assertTrue(isUdpOffloadSupportedByKernel("4.19.176"));
- assertTrue(isUdpOffloadSupportedByKernel("5.2.0"));
- assertTrue(isUdpOffloadSupportedByKernel("5.3.0"));
- assertFalse(isUdpOffloadSupportedByKernel("5.4.0"));
-
- assertFalse(isUdpOffloadSupportedByKernel("5.4.97"));
- assertTrue(isUdpOffloadSupportedByKernel("5.4.98"));
- assertTrue(isUdpOffloadSupportedByKernel("5.10.0"));
- }
-
- private static void assumeKernelSupportBpfOffloadUdpV4() {
- final String kernelVersion = VintfRuntimeInfo.getKernelVersion();
- assumeTrue("Kernel version " + kernelVersion + " doesn't support IPv4 UDP BPF offload",
- isUdpOffloadSupportedByKernel(kernelVersion));
- }
-
- @Test
- public void testKernelSupportBpfOffloadUdpV4() throws Exception {
- assumeKernelSupportBpfOffloadUdpV4();
- }
-
- @Test
- public void testTetherConfigBpfOffloadEnabled() throws Exception {
- assumeTrue(isTetherConfigBpfOffloadEnabled());
}
/**
@@ -674,73 +519,7 @@
*/
@Test
public void testTetherUdpV4() throws Exception {
- runUdp4Test(false /* verifyBpf */);
- }
-
- /**
- * BPF offload IPv4 UDP tethering test. Verify that UDP tethered packets are offloaded by BPF.
- * Minimum test requirement:
- * 1. S+ device.
- * 2. Tethering config enables tethering BPF offload.
- * 3. Kernel supports IPv4 UDP BPF offload. See #isUdpOffloadSupportedByKernel.
- *
- * TODO: consider enabling the test even tethering config disables BPF offload. See b/238288883
- */
- @Test
- @IgnoreUpTo(Build.VERSION_CODES.R)
- public void testTetherUdpV4_VerifyBpf() throws Exception {
- assumeTrue("Tethering config disabled BPF offload", isTetherConfigBpfOffloadEnabled());
- assumeKernelSupportBpfOffloadUdpV4();
-
- runUdp4Test(true /* verifyBpf */);
- }
-
- @NonNull
- private <K extends Struct, V extends Struct> HashMap<K, V> dumpAndParseRawMap(
- Class<K> keyClass, Class<V> valueClass, @NonNull String mapArg)
- throws Exception {
- final String[] args = new String[] {DUMPSYS_TETHERING_RAWMAP_ARG, mapArg};
- final String rawMapStr = runAsShell(DUMP, () ->
- DumpTestUtils.dumpService(Context.TETHERING_SERVICE, args));
- final HashMap<K, V> map = new HashMap<>();
-
- for (final String line : rawMapStr.split(LINE_DELIMITER)) {
- final Pair<K, V> rule =
- BpfDump.fromBase64EncodedString(keyClass, valueClass, line.trim());
- map.put(rule.first, rule.second);
- }
- return map;
- }
-
- @Nullable
- private <K extends Struct, V extends Struct> HashMap<K, V> pollRawMapFromDump(
- Class<K> keyClass, Class<V> valueClass, @NonNull String mapArg)
- throws Exception {
- for (int retryCount = 0; retryCount < DUMP_POLLING_MAX_RETRY; retryCount++) {
- final HashMap<K, V> map = dumpAndParseRawMap(keyClass, valueClass, mapArg);
- if (!map.isEmpty()) return map;
-
- Thread.sleep(DUMP_POLLING_INTERVAL_MS);
- }
-
- fail("Cannot get rules after " + DUMP_POLLING_MAX_RETRY * DUMP_POLLING_INTERVAL_MS + "ms");
- return null;
- }
-
- private boolean isTetherConfigBpfOffloadEnabled() throws Exception {
- final String dumpStr = runAsShell(DUMP, () ->
- DumpTestUtils.dumpService(Context.TETHERING_SERVICE, "--short"));
-
- // BPF offload tether config can be overridden by "config_tether_enable_bpf_offload" in
- // packages/modules/Connectivity/Tethering/res/values/config.xml. OEM may disable config by
- // RRO to override the enabled default value. Get the tethering config via dumpsys.
- // $ dumpsys tethering
- // mIsBpfEnabled: true
- boolean enabled = dumpStr.contains("mIsBpfEnabled: true");
- if (!enabled) {
- Log.d(TAG, "BPF offload tether config not enabled: " + dumpStr);
- }
- return enabled;
+ runUdp4Test();
}
@NonNull
diff --git a/Tethering/tests/mts/Android.bp b/Tethering/tests/mts/Android.bp
index ae36499..4f4b03c 100644
--- a/Tethering/tests/mts/Android.bp
+++ b/Tethering/tests/mts/Android.bp
@@ -33,6 +33,7 @@
],
static_libs: [
+ "TetheringIntegrationTestsBaseLib",
"androidx.test.rules",
// mockito-target-extended-minus-junit4 used in this lib have dependency with
// jni_libs libdexmakerjvmtiagent and libstaticjvmtiagent.
diff --git a/Tethering/tests/mts/src/android/tethering/mts/MtsEthernetTetheringTest.java b/Tethering/tests/mts/src/android/tethering/mts/MtsEthernetTetheringTest.java
new file mode 100644
index 0000000..cb57d13
--- /dev/null
+++ b/Tethering/tests/mts/src/android/tethering/mts/MtsEthernetTetheringTest.java
@@ -0,0 +1,304 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import static android.Manifest.permission.DUMP;
+import static android.system.OsConstants.IPPROTO_UDP;
+
+import static com.android.testutils.DeviceInfoUtils.KVersion;
+import static com.android.testutils.TestPermissionUtil.runAsShell;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
+
+import android.content.Context;
+import android.net.TetheringTester.TetheredDevice;
+import android.os.Build;
+import android.os.VintfRuntimeInfo;
+import android.util.Log;
+import android.util.Pair;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.test.filters.MediumTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.net.module.util.BpfDump;
+import com.android.net.module.util.Struct;
+import com.android.net.module.util.bpf.Tether4Key;
+import com.android.net.module.util.bpf.Tether4Value;
+import com.android.net.module.util.bpf.TetherStatsKey;
+import com.android.net.module.util.bpf.TetherStatsValue;
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
+import com.android.testutils.DeviceInfoUtils;
+import com.android.testutils.DumpTestUtils;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.net.InetAddress;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+public class MtsEthernetTetheringTest extends EthernetTetheringTestBase {
+ @Rule
+ public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule();
+
+ private static final String TAG = MtsEthernetTetheringTest.class.getSimpleName();
+
+ private static final int DUMP_POLLING_MAX_RETRY = 100;
+ private static final int DUMP_POLLING_INTERVAL_MS = 50;
+ // Kernel treats a confirmed UDP connection which active after two seconds as stream mode.
+ // See upstream commit b7b1d02fc43925a4d569ec221715db2dfa1ce4f5.
+ private static final int UDP_STREAM_TS_MS = 2000;
+ // Give slack time for waiting UDP stream mode because handling conntrack event in user space
+ // may not in precise time. Used to reduce the flaky rate.
+ private static final int UDP_STREAM_SLACK_MS = 500;
+ // Per RX UDP packet size: iphdr (20) + udphdr (8) + payload (2) = 30 bytes.
+ private static final int RX_UDP_PACKET_SIZE = 30;
+ private static final int RX_UDP_PACKET_COUNT = 456;
+ // Per TX UDP packet size: ethhdr (14) + iphdr (20) + udphdr (8) + payload (2) = 44 bytes.
+ private static final int TX_UDP_PACKET_SIZE = 44;
+ private static final int TX_UDP_PACKET_COUNT = 123;
+
+ private static final String DUMPSYS_TETHERING_RAWMAP_ARG = "bpfRawMap";
+ private static final String DUMPSYS_RAWMAP_ARG_STATS = "--stats";
+ private static final String DUMPSYS_RAWMAP_ARG_UPSTREAM4 = "--upstream4";
+ private static final String LINE_DELIMITER = "\\n";
+
+ private static boolean isUdpOffloadSupportedByKernel(final String kernelVersion) {
+ final KVersion current = DeviceInfoUtils.getMajorMinorSubminorVersion(kernelVersion);
+ return current.isInRange(new KVersion(4, 14, 222), new KVersion(4, 19, 0))
+ || current.isInRange(new KVersion(4, 19, 176), new KVersion(5, 4, 0))
+ || current.isAtLeast(new KVersion(5, 4, 98));
+ }
+
+ @Test
+ public void testIsUdpOffloadSupportedByKernel() throws Exception {
+ assertFalse(isUdpOffloadSupportedByKernel("4.14.221"));
+ assertTrue(isUdpOffloadSupportedByKernel("4.14.222"));
+ assertTrue(isUdpOffloadSupportedByKernel("4.16.0"));
+ assertTrue(isUdpOffloadSupportedByKernel("4.18.0"));
+ assertFalse(isUdpOffloadSupportedByKernel("4.19.0"));
+
+ assertFalse(isUdpOffloadSupportedByKernel("4.19.175"));
+ assertTrue(isUdpOffloadSupportedByKernel("4.19.176"));
+ assertTrue(isUdpOffloadSupportedByKernel("5.2.0"));
+ assertTrue(isUdpOffloadSupportedByKernel("5.3.0"));
+ assertFalse(isUdpOffloadSupportedByKernel("5.4.0"));
+
+ assertFalse(isUdpOffloadSupportedByKernel("5.4.97"));
+ assertTrue(isUdpOffloadSupportedByKernel("5.4.98"));
+ assertTrue(isUdpOffloadSupportedByKernel("5.10.0"));
+ }
+
+ private static void assumeKernelSupportBpfOffloadUdpV4() {
+ final String kernelVersion = VintfRuntimeInfo.getKernelVersion();
+ assumeTrue("Kernel version " + kernelVersion + " doesn't support IPv4 UDP BPF offload",
+ isUdpOffloadSupportedByKernel(kernelVersion));
+ }
+
+ @Test
+ public void testKernelSupportBpfOffloadUdpV4() throws Exception {
+ assumeKernelSupportBpfOffloadUdpV4();
+ }
+
+ private boolean isTetherConfigBpfOffloadEnabled() throws Exception {
+ final String dumpStr = runAsShell(DUMP, () ->
+ DumpTestUtils.dumpService(Context.TETHERING_SERVICE, "--short"));
+
+ // BPF offload tether config can be overridden by "config_tether_enable_bpf_offload" in
+ // packages/modules/Connectivity/Tethering/res/values/config.xml. OEM may disable config by
+ // RRO to override the enabled default value. Get the tethering config via dumpsys.
+ // $ dumpsys tethering
+ // mIsBpfEnabled: true
+ boolean enabled = dumpStr.contains("mIsBpfEnabled: true");
+ if (!enabled) {
+ Log.d(TAG, "BPF offload tether config not enabled: " + dumpStr);
+ }
+ return enabled;
+ }
+
+ @Test
+ public void testTetherConfigBpfOffloadEnabled() throws Exception {
+ assumeTrue(isTetherConfigBpfOffloadEnabled());
+ }
+
+ @NonNull
+ private <K extends Struct, V extends Struct> HashMap<K, V> dumpAndParseRawMap(
+ Class<K> keyClass, Class<V> valueClass, @NonNull String mapArg)
+ throws Exception {
+ final String[] args = new String[] {DUMPSYS_TETHERING_RAWMAP_ARG, mapArg};
+ final String rawMapStr = runAsShell(DUMP, () ->
+ DumpTestUtils.dumpService(Context.TETHERING_SERVICE, args));
+ final HashMap<K, V> map = new HashMap<>();
+
+ for (final String line : rawMapStr.split(LINE_DELIMITER)) {
+ final Pair<K, V> rule =
+ BpfDump.fromBase64EncodedString(keyClass, valueClass, line.trim());
+ map.put(rule.first, rule.second);
+ }
+ return map;
+ }
+
+ @Nullable
+ private <K extends Struct, V extends Struct> HashMap<K, V> pollRawMapFromDump(
+ Class<K> keyClass, Class<V> valueClass, @NonNull String mapArg)
+ throws Exception {
+ for (int retryCount = 0; retryCount < DUMP_POLLING_MAX_RETRY; retryCount++) {
+ final HashMap<K, V> map = dumpAndParseRawMap(keyClass, valueClass, mapArg);
+ if (!map.isEmpty()) return map;
+
+ Thread.sleep(DUMP_POLLING_INTERVAL_MS);
+ }
+
+ fail("Cannot get rules after " + DUMP_POLLING_MAX_RETRY * DUMP_POLLING_INTERVAL_MS + "ms");
+ return null;
+ }
+
+ // 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 {
+ final TetheringTester tester = initTetheringTester(toList(TEST_IP4_ADDR),
+ toList(TEST_IP4_DNS));
+ final TetheredDevice tethered = tester.createTetheredDevice(TEST_MAC, false /* hasIpv6 */);
+
+ // TODO: remove the connectivity verification for upstream connected notification race.
+ // Because async upstream connected notification can't guarantee the tethering routing is
+ // ready to use. Need to test tethering connectivity before testing.
+ // For short term plan, consider using IPv6 RA to get MAC address because the prefix comes
+ // from upstream. That can guarantee that the routing is ready. Long term plan is that
+ // refactors upstream connected notification from async to sync.
+ probeV4TetheringConnectivity(tester, tethered, false /* is4To6 */);
+
+ final MacAddress srcMac = tethered.macAddr;
+ final MacAddress dstMac = tethered.routerMacAddr;
+ final InetAddress remoteIp = REMOTE_IP4_ADDR;
+ final InetAddress tetheringUpstreamIp = TEST_IP4_ADDR.getAddress();
+ final InetAddress clientIp = tethered.ipv4Addr;
+ sendUploadPacketUdp(srcMac, dstMac, clientIp, remoteIp, tester, false /* is4To6 */);
+ sendDownloadPacketUdp(remoteIp, tetheringUpstreamIp, tester, false /* is6To4 */);
+
+ // Send second UDP packet in original direction.
+ // The BPF coordinator only offloads the ASSURED conntrack entry. The "request + reply"
+ // packets can make status IPS_SEEN_REPLY to be set. Need one more packet to make
+ // conntrack status IPS_ASSURED_BIT to be set. Note the third packet needs to delay
+ // 2 seconds because kernel monitors a UDP connection which still alive after 2 seconds
+ // and apply ASSURED flag.
+ // See kernel upstream commit b7b1d02fc43925a4d569ec221715db2dfa1ce4f5 and
+ // nf_conntrack_udp_packet in net/netfilter/nf_conntrack_proto_udp.c
+ Thread.sleep(UDP_STREAM_TS_MS);
+ sendUploadPacketUdp(srcMac, dstMac, clientIp, remoteIp, tester, false /* is4To6 */);
+
+ // Give a slack time for handling conntrack event in user space.
+ Thread.sleep(UDP_STREAM_SLACK_MS);
+
+ // [1] Verify IPv4 upstream rule map.
+ final HashMap<Tether4Key, Tether4Value> upstreamMap = pollRawMapFromDump(
+ Tether4Key.class, Tether4Value.class, DUMPSYS_RAWMAP_ARG_UPSTREAM4);
+ assertNotNull(upstreamMap);
+ assertEquals(1, upstreamMap.size());
+
+ final Map.Entry<Tether4Key, Tether4Value> rule =
+ upstreamMap.entrySet().iterator().next();
+
+ final Tether4Key upstream4Key = rule.getKey();
+ assertEquals(IPPROTO_UDP, upstream4Key.l4proto);
+ assertTrue(Arrays.equals(tethered.ipv4Addr.getAddress(), upstream4Key.src4));
+ assertEquals(LOCAL_PORT, upstream4Key.srcPort);
+ assertTrue(Arrays.equals(REMOTE_IP4_ADDR.getAddress(), upstream4Key.dst4));
+ assertEquals(REMOTE_PORT, upstream4Key.dstPort);
+
+ final Tether4Value upstream4Value = rule.getValue();
+ assertTrue(Arrays.equals(tetheringUpstreamIp.getAddress(),
+ InetAddress.getByAddress(upstream4Value.src46).getAddress()));
+ assertEquals(LOCAL_PORT, upstream4Value.srcPort);
+ assertTrue(Arrays.equals(REMOTE_IP4_ADDR.getAddress(),
+ InetAddress.getByAddress(upstream4Value.dst46).getAddress()));
+ assertEquals(REMOTE_PORT, upstream4Value.dstPort);
+
+ // [2] Verify stats map.
+ // Transmit packets on both direction for verifying stats. Because we only care the
+ // packet count in stats test, we just reuse the existing packets to increaes
+ // the packet count on both direction.
+
+ // Send packets on original direction.
+ for (int i = 0; i < TX_UDP_PACKET_COUNT; i++) {
+ sendUploadPacketUdp(srcMac, dstMac, clientIp, remoteIp, tester,
+ false /* is4To6 */);
+ }
+
+ // Send packets on reply direction.
+ for (int i = 0; i < RX_UDP_PACKET_COUNT; i++) {
+ sendDownloadPacketUdp(remoteIp, tetheringUpstreamIp, tester, false /* is6To4 */);
+ }
+
+ // Dump stats map to verify.
+ final HashMap<TetherStatsKey, TetherStatsValue> statsMap = pollRawMapFromDump(
+ TetherStatsKey.class, TetherStatsValue.class, DUMPSYS_RAWMAP_ARG_STATS);
+ assertNotNull(statsMap);
+ assertEquals(1, statsMap.size());
+
+ final Map.Entry<TetherStatsKey, TetherStatsValue> stats =
+ statsMap.entrySet().iterator().next();
+
+ // TODO: verify the upstream index in TetherStatsKey.
+
+ final TetherStatsValue statsValue = stats.getValue();
+ assertEquals(RX_UDP_PACKET_COUNT, statsValue.rxPackets);
+ assertEquals(RX_UDP_PACKET_COUNT * RX_UDP_PACKET_SIZE, statsValue.rxBytes);
+ assertEquals(0, statsValue.rxErrors);
+ assertEquals(TX_UDP_PACKET_COUNT, statsValue.txPackets);
+ assertEquals(TX_UDP_PACKET_COUNT * TX_UDP_PACKET_SIZE, statsValue.txBytes);
+ assertEquals(0, statsValue.txErrors);
+ }
+
+ /**
+ * BPF offload IPv4 UDP tethering test. Verify that UDP tethered packets are offloaded by BPF.
+ * Minimum test requirement:
+ * 1. S+ device.
+ * 2. Tethering config enables tethering BPF offload.
+ * 3. Kernel supports IPv4 UDP BPF offload. See #isUdpOffloadSupportedByKernel.
+ *
+ * TODO: consider enabling the test even tethering config disables BPF offload. See b/238288883
+ */
+ @Test
+ @IgnoreUpTo(Build.VERSION_CODES.R)
+ public void testTetherBpfOffloadUdpV4() throws Exception {
+ assumeTrue("Tethering config disabled BPF offload", isTetherConfigBpfOffloadEnabled());
+ assumeKernelSupportBpfOffloadUdpV4();
+
+ runUdp4Test();
+ }
+}
diff --git a/framework/api/module-lib-current.txt b/framework/api/module-lib-current.txt
index f623b05..193bd92 100644
--- a/framework/api/module-lib-current.txt
+++ b/framework/api/module-lib-current.txt
@@ -15,7 +15,7 @@
method @Nullable @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public android.net.LinkProperties getRedactedLinkPropertiesForPackage(@NonNull android.net.LinkProperties, int, @NonNull String);
method @Nullable @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public android.net.NetworkCapabilities getRedactedNetworkCapabilitiesForPackage(@NonNull android.net.NetworkCapabilities, int, @NonNull String);
method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void registerDefaultNetworkCallbackForUid(int, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
- method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS}) public void registerSystemDefaultNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
+ method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS}) public void registerSystemDefaultNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void removeUidFromMeteredNetworkAllowList(int);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void removeUidFromMeteredNetworkDenyList(int);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void replaceFirewallChain(int, @NonNull int[]);
diff --git a/framework/api/system-current.txt b/framework/api/system-current.txt
index 0b03983..196e023 100644
--- a/framework/api/system-current.txt
+++ b/framework/api/system-current.txt
@@ -470,7 +470,7 @@
}
public abstract class SocketKeepalive implements java.lang.AutoCloseable {
- method public final void start(@IntRange(from=0xa, to=0xe10) int, int);
+ method public final void start(@IntRange(from=0xa, to=0xe10) int, int, @NonNull android.net.Network);
field public static final int ERROR_NO_SUCH_SLOT = -33; // 0xffffffdf
field public static final int FLAG_AUTOMATIC_ON_OFF = 1; // 0x1
field public static final int SUCCESS = 0; // 0x0
diff --git a/framework/src/android/net/ConnectivityManager.java b/framework/src/android/net/ConnectivityManager.java
index 79c94ab..7cef58b 100644
--- a/framework/src/android/net/ConnectivityManager.java
+++ b/framework/src/android/net/ConnectivityManager.java
@@ -4901,6 +4901,7 @@
@RequiresPermission(anyOf = {
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
android.Manifest.permission.NETWORK_SETTINGS,
+ android.Manifest.permission.NETWORK_SETUP_WIZARD,
android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS})
public void registerSystemDefaultNetworkCallback(@NonNull NetworkCallback networkCallback,
@NonNull Handler handler) {
@@ -6035,6 +6036,30 @@
}
/**
+ * Get firewall rule of specified firewall chain on specified uid.
+ *
+ * @param chain target chain.
+ * @param uid target uid
+ * @return either FIREWALL_RULE_ALLOW or FIREWALL_RULE_DENY
+ * @throws UnsupportedOperationException if called on pre-T devices.
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ * @hide
+ */
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.NETWORK_SETTINGS,
+ android.Manifest.permission.NETWORK_STACK,
+ NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
+ })
+ public int getUidFirewallRule(@FirewallChain final int chain, final int uid) {
+ try {
+ return mService.getUidFirewallRule(chain, uid);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Enables or disables the specified firewall chain.
*
* @param chain target chain.
diff --git a/framework/src/android/net/IConnectivityManager.aidl b/framework/src/android/net/IConnectivityManager.aidl
index c8f588d..1372e9a 100644
--- a/framework/src/android/net/IConnectivityManager.aidl
+++ b/framework/src/android/net/IConnectivityManager.aidl
@@ -188,7 +188,7 @@
void startNattKeepaliveWithFd(in Network network, in ParcelFileDescriptor pfd, int resourceId,
int intervalSeconds, in ISocketKeepaliveCallback cb, String srcAddr,
- String dstAddr, boolean automaticOnOffKeepalives);
+ String dstAddr, boolean automaticOnOffKeepalives, in Network underpinnedNetwork);
void startTcpKeepalive(in Network network, in ParcelFileDescriptor pfd, int intervalSeconds,
in ISocketKeepaliveCallback cb);
@@ -242,6 +242,8 @@
void setUidFirewallRule(int chain, int uid, int rule);
+ int getUidFirewallRule(int chain, int uid);
+
void setFirewallChainEnabled(int chain, boolean enable);
boolean getFirewallChainEnabled(int chain);
diff --git a/framework/src/android/net/NattSocketKeepalive.java b/framework/src/android/net/NattSocketKeepalive.java
index 77137f4..a83b5b4 100644
--- a/framework/src/android/net/NattSocketKeepalive.java
+++ b/framework/src/android/net/NattSocketKeepalive.java
@@ -66,10 +66,12 @@
* the supplied {@link Callback} will see a call to
* {@link Callback#onError(int)} with {@link #ERROR_INVALID_INTERVAL}.
* @param flags Flags to enable/disable available options on this keepalive.
+ * @param underpinnedNetwork The underpinned network of this keepalive.
+ *
* @hide
*/
@Override
- protected void startImpl(int intervalSec, int flags) {
+ protected void startImpl(int intervalSec, int flags, Network underpinnedNetwork) {
if (0 != (flags & ~FLAG_AUTOMATIC_ON_OFF)) {
throw new IllegalArgumentException("Illegal flag value for "
+ this.getClass().getSimpleName() + " : " + flags);
@@ -79,7 +81,8 @@
try {
mService.startNattKeepaliveWithFd(mNetwork, mPfd, mResourceId,
intervalSec, mCallback, mSource.getHostAddress(),
- mDestination.getHostAddress(), automaticOnOffKeepalives);
+ mDestination.getHostAddress(), automaticOnOffKeepalives,
+ underpinnedNetwork);
} catch (RemoteException e) {
Log.e(TAG, "Error starting socket keepalive: ", e);
throw e.rethrowFromSystemServer();
diff --git a/framework/src/android/net/SocketKeepalive.java b/framework/src/android/net/SocketKeepalive.java
index 00104f6..311126e 100644
--- a/framework/src/android/net/SocketKeepalive.java
+++ b/framework/src/android/net/SocketKeepalive.java
@@ -355,7 +355,7 @@
*/
public final void start(@IntRange(from = MIN_INTERVAL_SEC, to = MAX_INTERVAL_SEC)
int intervalSec) {
- startImpl(intervalSec, 0 /* flags */);
+ startImpl(intervalSec, 0 /* flags */, null /* underpinnedNetwork */);
}
/**
@@ -374,16 +374,18 @@
* the supplied {@link Callback} will see a call to
* {@link Callback#onError(int)} with {@link #ERROR_INVALID_INTERVAL}.
* @param flags Flags to enable/disable available options on this keepalive.
+ * @param underpinnedNetwork The underpinned network of this keepalive.
* @hide
*/
@SystemApi(client = PRIVILEGED_APPS)
public final void start(@IntRange(from = MIN_INTERVAL_SEC, to = MAX_INTERVAL_SEC)
- int intervalSec, @StartFlags int flags) {
- startImpl(intervalSec, flags);
+ int intervalSec, @StartFlags int flags, @NonNull Network underpinnedNetwork) {
+ startImpl(intervalSec, flags, underpinnedNetwork);
}
/** @hide */
- protected abstract void startImpl(int intervalSec, @StartFlags int flags);
+ protected abstract void startImpl(int intervalSec, @StartFlags int flags,
+ Network underpinnedNetwork);
/**
* Requests that keepalive be stopped. The application must wait for {@link Callback#onStopped}
diff --git a/framework/src/android/net/TcpSocketKeepalive.java b/framework/src/android/net/TcpSocketKeepalive.java
index cda5830..b548f6d 100644
--- a/framework/src/android/net/TcpSocketKeepalive.java
+++ b/framework/src/android/net/TcpSocketKeepalive.java
@@ -50,7 +50,7 @@
* acknowledgement.
*/
@Override
- protected void startImpl(int intervalSec, int flags) {
+ protected void startImpl(int intervalSec, int flags, Network underpinnedNetwork) {
if (0 != flags) {
throw new IllegalArgumentException("Illegal flag value for "
+ this.getClass().getSimpleName() + " : " + flags);
diff --git a/service-t/jni/com_android_server_net_NetworkStatsFactory.cpp b/service-t/jni/com_android_server_net_NetworkStatsFactory.cpp
index a3299a7..2dbe771 100644
--- a/service-t/jni/com_android_server_net_NetworkStatsFactory.cpp
+++ b/service-t/jni/com_android_server_net_NetworkStatsFactory.cpp
@@ -210,7 +210,8 @@
};
int register_android_server_net_NetworkStatsFactory(JNIEnv* env) {
- int err = jniRegisterNativeMethods(env, "com/android/server/net/NetworkStatsFactory", gMethods,
+ int err = jniRegisterNativeMethods(env,
+ "android/net/connectivity/com/android/server/net/NetworkStatsFactory", gMethods,
NELEM(gMethods));
gStringClass = env->FindClass("java/lang/String");
gStringClass = static_cast<jclass>(env->NewGlobalRef(gStringClass));
diff --git a/service-t/jni/com_android_server_net_NetworkStatsService.cpp b/service-t/jni/com_android_server_net_NetworkStatsService.cpp
index af0b8d8..dab9d07 100644
--- a/service-t/jni/com_android_server_net_NetworkStatsService.cpp
+++ b/service-t/jni/com_android_server_net_NetworkStatsService.cpp
@@ -116,8 +116,9 @@
};
int register_android_server_net_NetworkStatsService(JNIEnv* env) {
- return jniRegisterNativeMethods(env, "com/android/server/net/NetworkStatsService", gMethods,
- NELEM(gMethods));
+ return jniRegisterNativeMethods(env,
+ "android/net/connectivity/com/android/server/net/NetworkStatsService", gMethods,
+ NELEM(gMethods));
}
}
diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java
index 60485f1..eed9aeb 100644
--- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java
+++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java
@@ -469,9 +469,7 @@
// TODO: Update this logic to only do a restart if required. Although a restart may
// be required due to the capabilities or ipConfiguration values, not all
// capabilities changes require a restart.
- if (mIpClient != null) {
- restart();
- }
+ maybeRestart();
}
boolean isRestricted() {
@@ -549,7 +547,7 @@
// Send a callback in case a provisioning request was in progress.
return;
}
- restart();
+ maybeRestart();
}
private void ensureRunningOnEthernetHandlerThread() {
@@ -582,7 +580,7 @@
// If there is a better network, that will become default and apps
// will be able to use internet. If ethernet gets connected again,
// and has backhaul connectivity, it will become default.
- restart();
+ maybeRestart();
}
/** Returns true if state has been modified */
@@ -656,18 +654,16 @@
.build();
}
- void restart() {
- if (DBG) Log.d(TAG, "restart IpClient");
-
+ void maybeRestart() {
if (mIpClient == null) {
- // If restart() is called from a provisioning failure, it is
+ // If maybeRestart() is called from a provisioning failure, it is
// possible that link disappeared in the meantime. In that
// case, stop() has already been called and IpClient should not
// get restarted to prevent a provisioning failure loop.
- Log.i(TAG, String.format("restart() was called on stopped interface %s", name));
+ Log.i(TAG, String.format("maybeRestart() called on stopped interface %s", name));
return;
}
-
+ if (DBG) Log.d(TAG, "restart IpClient");
stop();
start();
}
diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java
index 1606fd0..2346244 100644
--- a/service-t/src/com/android/server/net/NetworkStatsService.java
+++ b/service-t/src/com/android/server/net/NetworkStatsService.java
@@ -2423,20 +2423,41 @@
xtTotal = mXtRecorder.getTotalSinceBootLocked(template);
uidTotal = mUidRecorder.getTotalSinceBootLocked(template);
- EventLog.writeEvent(LOG_TAG_NETSTATS_MOBILE_SAMPLE,
- xtTotal.rxBytes, xtTotal.rxPackets, xtTotal.txBytes, xtTotal.txPackets,
- uidTotal.rxBytes, uidTotal.rxPackets, uidTotal.txBytes, uidTotal.txPackets,
- currentTime);
+ if (SdkLevel.isAtLeastU()) {
+ EventLog.writeEvent(LOG_TAG_NETSTATS_MOBILE_SAMPLE,
+ xtTotal.rxBytes, xtTotal.rxPackets, xtTotal.txBytes, xtTotal.txPackets,
+ uidTotal.rxBytes, uidTotal.rxPackets, uidTotal.txBytes, uidTotal.txPackets,
+ currentTime);
+ } else {
+ // To keep the format of event log, here replaces the value of DevRecorder with the
+ // value of XtRecorder because they have the same content in old design.
+ EventLog.writeEvent(LOG_TAG_NETSTATS_MOBILE_SAMPLE,
+ xtTotal.rxBytes, xtTotal.rxPackets, xtTotal.txBytes, xtTotal.txPackets,
+ xtTotal.rxBytes, xtTotal.rxPackets, xtTotal.txBytes, xtTotal.txPackets,
+ uidTotal.rxBytes, uidTotal.rxPackets, uidTotal.txBytes, uidTotal.txPackets,
+ currentTime);
+ }
// collect wifi sample
template = new NetworkTemplate.Builder(MATCH_WIFI).build();
xtTotal = mXtRecorder.getTotalSinceBootLocked(template);
uidTotal = mUidRecorder.getTotalSinceBootLocked(template);
- EventLog.writeEvent(LOG_TAG_NETSTATS_WIFI_SAMPLE,
- xtTotal.rxBytes, xtTotal.rxPackets, xtTotal.txBytes, xtTotal.txPackets,
- uidTotal.rxBytes, uidTotal.rxPackets, uidTotal.txBytes, uidTotal.txPackets,
- currentTime);
+ if (SdkLevel.isAtLeastU()) {
+ EventLog.writeEvent(LOG_TAG_NETSTATS_WIFI_SAMPLE,
+ xtTotal.rxBytes, xtTotal.rxPackets, xtTotal.txBytes, xtTotal.txPackets,
+ uidTotal.rxBytes, uidTotal.rxPackets, uidTotal.txBytes, uidTotal.txPackets,
+ currentTime);
+ } else {
+ // To keep the format of event log, here replaces the value of DevRecorder with the
+ // value of XtRecorder because they have the same content in old design.
+ EventLog.writeEvent(LOG_TAG_NETSTATS_WIFI_SAMPLE,
+ xtTotal.rxBytes, xtTotal.rxPackets, xtTotal.txBytes, xtTotal.txPackets,
+ xtTotal.rxBytes, xtTotal.rxPackets, xtTotal.txBytes, xtTotal.txPackets,
+ uidTotal.rxBytes, uidTotal.rxPackets, uidTotal.txBytes, uidTotal.txPackets,
+ currentTime);
+
+ }
}
// deleteKernelTagData can ignore ENOENT; otherwise we should log an error
diff --git a/service/jarjar-excludes.txt b/service/jarjar-excludes.txt
index b0d6763..7bd3862 100644
--- a/service/jarjar-excludes.txt
+++ b/service/jarjar-excludes.txt
@@ -1,9 +1,3 @@
# Classes loaded by SystemServer via their hardcoded name, so they can't be jarjared
com\.android\.server\.ConnectivityServiceInitializer(\$.+)?
com\.android\.server\.NetworkStatsServiceInitializer(\$.+)?
-
-# Do not jarjar com.android.server, as several unit tests fail because they lose
-# package-private visibility between jarjared and non-jarjared classes.
-# TODO: fix the tests and also jarjar com.android.server, or at least only exclude a package that
-# is specific to the module like com.android.server.connectivity
-com\.android\.server\..+
diff --git a/service/jni/com_android_server_BpfNetMaps.cpp b/service/jni/com_android_server_BpfNetMaps.cpp
index 05f50b0..77cffda 100644
--- a/service/jni/com_android_server_BpfNetMaps.cpp
+++ b/service/jni/com_android_server_BpfNetMaps.cpp
@@ -236,7 +236,7 @@
// clang-format on
int register_com_android_server_BpfNetMaps(JNIEnv* env) {
- return jniRegisterNativeMethods(env, "com/android/server/BpfNetMaps",
+ return jniRegisterNativeMethods(env, "android/net/connectivity/com/android/server/BpfNetMaps",
gMethods, NELEM(gMethods));
}
diff --git a/service/jni/com_android_server_TestNetworkService.cpp b/service/jni/com_android_server_TestNetworkService.cpp
index bd74d54..7aeecfa 100644
--- a/service/jni/com_android_server_TestNetworkService.cpp
+++ b/service/jni/com_android_server_TestNetworkService.cpp
@@ -151,8 +151,9 @@
};
int register_com_android_server_TestNetworkService(JNIEnv* env) {
- return jniRegisterNativeMethods(env, "com/android/server/TestNetworkService", gMethods,
- NELEM(gMethods));
+ return jniRegisterNativeMethods(env,
+ "android/net/connectivity/com/android/server/TestNetworkService", gMethods,
+ NELEM(gMethods));
}
}; // namespace android
diff --git a/service/jni/com_android_server_connectivity_ClatCoordinator.cpp b/service/jni/com_android_server_connectivity_ClatCoordinator.cpp
index 7060958..5b42659 100644
--- a/service/jni/com_android_server_connectivity_ClatCoordinator.cpp
+++ b/service/jni/com_android_server_connectivity_ClatCoordinator.cpp
@@ -477,8 +477,9 @@
};
int register_com_android_server_connectivity_ClatCoordinator(JNIEnv* env) {
- return jniRegisterNativeMethods(env, "com/android/server/connectivity/ClatCoordinator",
- gMethods, NELEM(gMethods));
+ return jniRegisterNativeMethods(env,
+ "android/net/connectivity/com/android/server/connectivity/ClatCoordinator",
+ gMethods, NELEM(gMethods));
}
}; // namespace android
diff --git a/service/proguard.flags b/service/proguard.flags
index 864a28b..cf25f05 100644
--- a/service/proguard.flags
+++ b/service/proguard.flags
@@ -7,7 +7,7 @@
*;
}
--keepclassmembers class com.android.server.**,android.net.**,com.android.networkstack.** {
+-keepclassmembers class android.net.**,com.android.networkstack.** {
static final % POLICY_*;
static final % NOTIFY_TYPE_*;
static final % TRANSPORT_*;
diff --git a/service/src/com/android/server/BpfNetMaps.java b/service/src/com/android/server/BpfNetMaps.java
index 26ec37a..b4fce37 100644
--- a/service/src/com/android/server/BpfNetMaps.java
+++ b/service/src/com/android/server/BpfNetMaps.java
@@ -721,6 +721,31 @@
}
/**
+ * Get firewall rule of specified firewall chain on specified uid.
+ *
+ * @param childChain target chain
+ * @param uid target uid
+ * @return either FIREWALL_RULE_ALLOW or FIREWALL_RULE_DENY
+ * @throws UnsupportedOperationException if called on pre-T devices.
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ */
+ public int getUidRule(final int childChain, final int uid) {
+ throwIfPreT("isUidChainEnabled is not available on pre-T devices");
+
+ final long match = getMatchByFirewallChain(childChain);
+ final boolean isAllowList = isFirewallAllowList(childChain);
+ try {
+ final UidOwnerValue uidMatch = sUidOwnerMap.getValue(new S32(uid));
+ final boolean isMatchEnabled = uidMatch != null && (uidMatch.rule & match) != 0;
+ return isMatchEnabled == isAllowList ? FIREWALL_RULE_ALLOW : FIREWALL_RULE_DENY;
+ } catch (ErrnoException e) {
+ throw new ServiceSpecificException(e.errno,
+ "Unable to get uid rule status: " + Os.strerror(e.errno));
+ }
+ }
+
+ /**
* Add ingress interface filtering rules to a list of UIDs
*
* For a given uid, once a filtering rule is added, the kernel will only allow packets from the
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index 1332f32..394292e 100755
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -2882,9 +2882,10 @@
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK);
}
- private void enforceSettingsOrUseRestrictedNetworksPermission() {
+ private void enforceSettingsOrSetupWizardOrUseRestrictedNetworksPermission() {
enforceAnyPermissionOf(mContext,
android.Manifest.permission.NETWORK_SETTINGS,
+ android.Manifest.permission.NETWORK_SETUP_WIZARD,
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS);
}
@@ -5589,13 +5590,14 @@
mKeepaliveTracker.getKeepaliveForBinder((IBinder) msg.obj);
if (null == ki) return; // The callback was unregistered before the alarm fired
+ final Network underpinnedNetwork = ki.getUnderpinnedNetwork();
final Network network = ki.getNetwork();
boolean networkFound = false;
- final ArrayList<NetworkAgentInfo> vpnsRunningOnThisNetwork = new ArrayList<>();
+ boolean underpinnedNetworkFound = false;
for (NetworkAgentInfo n : mNetworkAgentInfos) {
if (n.network.equals(network)) networkFound = true;
- if (n.isVPN() && n.everConnected() && hasUnderlyingNetwork(n, network)) {
- vpnsRunningOnThisNetwork.add(n);
+ if (n.everConnected() && n.network.equals(underpinnedNetwork)) {
+ underpinnedNetworkFound = true;
}
}
@@ -5603,12 +5605,11 @@
// cleaned up already. There is no point trying to resume keepalives.
if (!networkFound) return;
- if (!vpnsRunningOnThisNetwork.isEmpty()) {
+ if (underpinnedNetworkFound) {
mKeepaliveTracker.handleMonitorAutomaticKeepalive(ki,
- // TODO: check all the VPNs running on top of this network
- vpnsRunningOnThisNetwork.get(0).network.netId);
+ underpinnedNetwork.netId);
} else {
- // If no VPN, then make sure the keepalive is running.
+ // If no underpinned network, then make sure the keepalive is running.
mKeepaliveTracker.handleMaybeResumeKeepalive(ki);
}
break;
@@ -6848,7 +6849,7 @@
enforceAccessPermission();
break;
case TRACK_SYSTEM_DEFAULT:
- enforceSettingsOrUseRestrictedNetworksPermission();
+ enforceSettingsOrSetupWizardOrUseRestrictedNetworksPermission();
networkCapabilities = new NetworkCapabilities(defaultNc);
break;
case BACKGROUND_REQUEST:
@@ -9868,21 +9869,22 @@
getNetworkAgentInfoForNetwork(network), null /* fd */,
intervalSeconds, cb, srcAddr, srcPort, dstAddr, NattSocketKeepalive.NATT_PORT,
// Keep behavior of the deprecated method as it is. Set automaticOnOffKeepalives to
- // false because there is no way and no plan to configure automaticOnOffKeepalives
- // in this deprecated method.
- false /* automaticOnOffKeepalives */);
+ // false and set the underpinned network to null because there is no way and no
+ // plan to configure automaticOnOffKeepalives or underpinnedNetwork in this
+ // deprecated method.
+ false /* automaticOnOffKeepalives */, null /* underpinnedNetwork */);
}
@Override
public void startNattKeepaliveWithFd(Network network, ParcelFileDescriptor pfd, int resourceId,
int intervalSeconds, ISocketKeepaliveCallback cb, String srcAddr,
- String dstAddr, boolean automaticOnOffKeepalives) {
+ String dstAddr, boolean automaticOnOffKeepalives, Network underpinnedNetwork) {
try {
final FileDescriptor fd = pfd.getFileDescriptor();
mKeepaliveTracker.startNattKeepalive(
getNetworkAgentInfoForNetwork(network), fd, resourceId,
- intervalSeconds, cb,
- srcAddr, dstAddr, NattSocketKeepalive.NATT_PORT, automaticOnOffKeepalives);
+ intervalSeconds, cb, srcAddr, dstAddr, NattSocketKeepalive.NATT_PORT,
+ automaticOnOffKeepalives, underpinnedNetwork);
} finally {
// FileDescriptors coming from AIDL calls must be manually closed to prevent leaks.
// startNattKeepalive calls Os.dup(fd) before returning, so we can close immediately.
@@ -11745,6 +11747,12 @@
}
}
+ @Override
+ public int getUidFirewallRule(final int chain, final int uid) {
+ enforceNetworkStackOrSettingsPermission();
+ return mBpfNetMaps.getUidRule(chain, uid);
+ }
+
private int getFirewallRuleType(int chain, int rule) {
final int defaultRule;
switch (chain) {
diff --git a/service/src/com/android/server/connectivity/AutomaticOnOffKeepaliveTracker.java b/service/src/com/android/server/connectivity/AutomaticOnOffKeepaliveTracker.java
index daabfd8..760a5f3 100644
--- a/service/src/com/android/server/connectivity/AutomaticOnOffKeepaliveTracker.java
+++ b/service/src/com/android/server/connectivity/AutomaticOnOffKeepaliveTracker.java
@@ -196,11 +196,16 @@
private final PendingIntent mTcpPollingAlarm;
@AutomaticOnOffState
private int mAutomaticOnOffState;
+ @Nullable
+ private final Network mUnderpinnedNetwork;
AutomaticOnOffKeepalive(@NonNull final KeepaliveTracker.KeepaliveInfo ki,
- final boolean autoOnOff, @NonNull Context context) throws InvalidSocketException {
+ final boolean autoOnOff, @NonNull Context context,
+ @Nullable Network underpinnedNetwork)
+ throws InvalidSocketException {
this.mKi = Objects.requireNonNull(ki);
mCallback = ki.mCallback;
+ mUnderpinnedNetwork = underpinnedNetwork;
if (autoOnOff && mDependencies.isFeatureEnabled(AUTOMATIC_ON_OFF_KEEPALIVE_VERSION)) {
mAutomaticOnOffState = STATE_ENABLED;
if (null == ki.mFd) {
@@ -228,6 +233,11 @@
return mKi.getNai().network;
}
+ @Nullable
+ public Network getUnderpinnedNetwork() {
+ return mUnderpinnedNetwork;
+ }
+
public boolean match(Network network, int slot) {
return mKi.getNai().network().equals(network) && mKi.getSlot() == slot;
}
@@ -475,13 +485,13 @@
@NonNull String srcAddrString,
int srcPort,
@NonNull String dstAddrString,
- int dstPort, boolean automaticOnOffKeepalives) {
+ int dstPort, boolean automaticOnOffKeepalives, @Nullable Network underpinnedNetwork) {
final KeepaliveTracker.KeepaliveInfo ki = mKeepaliveTracker.makeNattKeepaliveInfo(nai, fd,
intervalSeconds, cb, srcAddrString, srcPort, dstAddrString, dstPort);
if (null == ki) return;
try {
final AutomaticOnOffKeepalive autoKi = new AutomaticOnOffKeepalive(ki,
- automaticOnOffKeepalives, mContext);
+ automaticOnOffKeepalives, mContext, underpinnedNetwork);
mConnectivityServiceHandler.obtainMessage(NetworkAgent.CMD_START_SOCKET_KEEPALIVE,
// TODO : move ConnectivityService#encodeBool to a static lib.
automaticOnOffKeepalives ? 1 : 0, 0, autoKi).sendToTarget();
@@ -504,13 +514,14 @@
@NonNull String srcAddrString,
@NonNull String dstAddrString,
int dstPort,
- boolean automaticOnOffKeepalives) {
+ boolean automaticOnOffKeepalives,
+ @Nullable Network underpinnedNetwork) {
final KeepaliveTracker.KeepaliveInfo ki = mKeepaliveTracker.makeNattKeepaliveInfo(nai, fd,
resourceId, intervalSeconds, cb, srcAddrString, dstAddrString, dstPort);
if (null == ki) return;
try {
final AutomaticOnOffKeepalive autoKi = new AutomaticOnOffKeepalive(ki,
- automaticOnOffKeepalives, mContext);
+ automaticOnOffKeepalives, mContext, underpinnedNetwork);
mConnectivityServiceHandler.obtainMessage(NetworkAgent.CMD_START_SOCKET_KEEPALIVE,
// TODO : move ConnectivityService#encodeBool to a static lib.
automaticOnOffKeepalives ? 1 : 0, 0, autoKi).sendToTarget();
@@ -539,7 +550,8 @@
if (null == ki) return;
try {
final AutomaticOnOffKeepalive autoKi = new AutomaticOnOffKeepalive(ki,
- false /* autoOnOff, tcp keepalives are never auto on/off */, mContext);
+ false /* autoOnOff, tcp keepalives are never auto on/off */,
+ mContext, null /* underpinnedNetwork, tcp keepalives do not refer to this */);
mConnectivityServiceHandler.obtainMessage(CMD_START_SOCKET_KEEPALIVE, autoKi)
.sendToTarget();
} catch (InvalidSocketException e) {
diff --git a/tests/common/Android.bp b/tests/common/Android.bp
index 5c9cc63..8e47235 100644
--- a/tests/common/Android.bp
+++ b/tests/common/Android.bp
@@ -65,7 +65,7 @@
defaults: ["jarjar-rules-combine-defaults"],
srcs: [
"tethering-jni-jarjar-rules.txt",
- ":connectivity-jarjar-rules",
+ ":frameworks-net-tests-jarjar-rules",
":TetheringTestsJarJarRules",
":NetworkStackJarJarRules",
],
diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java
index d0567ae..2aa1032 100644
--- a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java
+++ b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java
@@ -31,6 +31,7 @@
import com.android.tradefed.testtype.IAbi;
import com.android.tradefed.testtype.IAbiReceiver;
import com.android.tradefed.testtype.IBuildReceiver;
+import com.android.tradefed.util.RunUtil;
import java.io.FileNotFoundException;
import java.util.Map;
@@ -120,7 +121,7 @@
i++;
Log.v(TAG, "Package " + packageName + " not uninstalled yet (" + result
+ "); sleeping 1s before polling again");
- Thread.sleep(1000);
+ RunUtil.getDefault().sleep(1000);
}
fail("Package '" + packageName + "' not uinstalled after " + max_tries + " seconds");
}
diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java
index 7a613b3..21c78b7 100644
--- a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java
+++ b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java
@@ -20,6 +20,7 @@
import com.android.ddmlib.Log;
import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.util.RunUtil;
public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestCase {
@@ -359,7 +360,7 @@
}
Log.v(TAG, "whitelist check for uid " + uid + " doesn't match yet (expected "
+ expected + ", got " + actual + "); sleeping 1s before polling again");
- Thread.sleep(1000);
+ RunUtil.getDefault().sleep(1000);
}
fail("whitelist check for uid " + uid + " failed: expected "
+ expected + ", got " + actual);
@@ -384,7 +385,7 @@
if (result.equals(expectedResult)) return;
Log.v(TAG, "Command '" + command + "' returned '" + result + " instead of '"
+ expectedResult + "' on attempt #; sleeping 1s before polling again");
- Thread.sleep(1000);
+ RunUtil.getDefault().sleep(1000);
}
fail("Command '" + command + "' did not return '" + expectedResult + "' after " + maxTries
+ " attempts");
diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
index 68b20e2..d2a3f91 100644
--- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -3409,12 +3409,16 @@
runWithShellPermissionIdentity(() -> {
// Firewall chain status will be restored after the test.
final boolean wasChainEnabled = mCm.getFirewallChainEnabled(chain);
+ final int previousUidFirewallRule = mCm.getUidFirewallRule(chain, myUid);
final DatagramSocket srcSock = new DatagramSocket();
final DatagramSocket dstSock = new DatagramSocket();
testAndCleanup(() -> {
if (wasChainEnabled) {
mCm.setFirewallChainEnabled(chain, false /* enable */);
}
+ if (previousUidFirewallRule == ruleToAddMatch) {
+ mCm.setUidFirewallRule(chain, myUid, ruleToRemoveMatch);
+ }
dstSock.setSoTimeout(SOCKET_TIMEOUT_MS);
// Chain disabled, UID not on chain.
@@ -3444,8 +3448,9 @@
// Restore the global chain status
mCm.setFirewallChainEnabled(chain, wasChainEnabled);
}, /* cleanup */ () -> {
+ // Restore the uid firewall rule status
try {
- mCm.setUidFirewallRule(chain, myUid, ruleToRemoveMatch);
+ mCm.setUidFirewallRule(chain, myUid, previousUidFirewallRule);
} catch (IllegalStateException ignored) {
// Removing match causes an exception when the rule entry for the uid does
// not exist. But this is fine and can be ignored.
diff --git a/tests/unit/Android.bp b/tests/unit/Android.bp
index 8db307d..36b3356 100644
--- a/tests/unit/Android.bp
+++ b/tests/unit/Android.bp
@@ -69,6 +69,7 @@
"java/com/android/server/VpnManagerServiceTest.java",
"java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java",
"java/com/android/server/connectivity/IpConnectivityMetricsTest.java",
+ "java/com/android/server/connectivity/MetricsTestUtil.java",
"java/com/android/server/connectivity/MultipathPolicyTrackerTest.java",
"java/com/android/server/connectivity/NetdEventListenerServiceTest.java",
"java/com/android/server/connectivity/VpnTest.java",
@@ -136,6 +137,37 @@
visibility: ["//packages/modules/Connectivity/tests:__subpackages__"],
}
+genrule {
+ name: "frameworks-net-tests-jarjar-rules",
+ defaults: ["jarjar-rules-combine-defaults"],
+ srcs: [
+ ":frameworks-net-tests-lib-jarjar-gen",
+ // This is necessary because the tests use framework-connectivity-internal-test-defaults,
+ // which require the user to use connectivity jarjar rules.
+ ":connectivity-jarjar-rules",
+ ],
+ out: ["frameworks-net-tests-jarjar-rules.txt"],
+ visibility: ["//packages/modules/Connectivity/tests:__subpackages__"],
+}
+
+java_genrule {
+ name: "frameworks-net-tests-lib-jarjar-gen",
+ tool_files: [
+ ":FrameworksNetTestsLib{.jar}",
+ "jarjar-excludes.txt",
+ ],
+ tools: [
+ "jarjar-rules-generator",
+ ],
+ out: ["frameworks-net-tests-lib-jarjar-rules.txt"],
+ cmd: "$(location jarjar-rules-generator) " +
+ "$(location :FrameworksNetTestsLib{.jar}) " +
+ "--prefix android.net.connectivity " +
+ "--excludes $(location jarjar-excludes.txt) " +
+ "--output $(out)",
+ visibility: ["//visibility:private"],
+}
+
android_test {
name: "FrameworksNetTests",
enabled: enable_frameworks_net_tests,
@@ -143,7 +175,7 @@
"FrameworksNetTestsDefaults",
"FrameworksNetTests-jni-defaults",
],
- jarjar_rules: ":connectivity-jarjar-rules",
+ jarjar_rules: ":frameworks-net-tests-jarjar-rules",
test_suites: ["device-tests"],
static_libs: [
"services.core",
diff --git a/tests/unit/AndroidManifest.xml b/tests/unit/AndroidManifest.xml
index 5bac2dd..5d4bdf7 100644
--- a/tests/unit/AndroidManifest.xml
+++ b/tests/unit/AndroidManifest.xml
@@ -63,7 +63,7 @@
<uses-library android:name="android.test.runner" />
<uses-library android:name="android.net.ipsec.ike" />
<activity
- android:name="com.android.server.connectivity.NetworkNotificationManagerTest$TestDialogActivity"/>
+ android:name="android.net.connectivity.com.android.server.connectivity.NetworkNotificationManagerTest$TestDialogActivity"/>
</application>
<instrumentation
diff --git a/tests/unit/jarjar-excludes.txt b/tests/unit/jarjar-excludes.txt
new file mode 100644
index 0000000..d2022bf
--- /dev/null
+++ b/tests/unit/jarjar-excludes.txt
@@ -0,0 +1,27 @@
+# Exclude some test prefixes, otherwise the classes reference below can't find
+# them after jarjared.
+android\.compat\..+
+androidx\.test\..+
+com\.android\.frameworks\.tests\..+
+com\.android\.testutils\..+
+com\.android\.dx\.mockito\..+
+com\.android\.internal\.compat\..+
+com\.android\.internal\.org\.bouncycastle\..+
+kotlin\.test\..+
+kotlin\.reflect\..+
+org\.junit\..+
+org\.mockito\..+
+
+# Auto-jarjar-gen can't handle kotlin object expression, exclude the tests which use
+# object expressions.
+#
+# For example: Illegal class access:
+# 'android.net.connectivity.com.android.net.module.util.TrackRecordTest' attempting to access
+# 'com.android.networkstack.tethering.util.TRTInterpreter' (declaration of
+# 'android.net.connectivity.com.android.net.module.util.TrackRecordTest' ...
+#
+# In coverage test, TRTInterpreter don't be jarjar'ed to
+# android.net.connectivity* by frameworks-net-tests-jarjar-rules instead it is
+# jarjar'ed by follow up TetheringTestsJarJarRules.
+# TODO(b/269259216): remove this after fixing Auto-jarjar-gen.
+com\.android\.net\.module\.util\.TrackRecord.*
diff --git a/tests/unit/java/android/net/Ikev2VpnProfileTest.java b/tests/unit/java/android/net/Ikev2VpnProfileTest.java
index 3b68120..e12e961 100644
--- a/tests/unit/java/android/net/Ikev2VpnProfileTest.java
+++ b/tests/unit/java/android/net/Ikev2VpnProfileTest.java
@@ -492,6 +492,29 @@
}
@Test
+ public void testAutomaticNattAndIpVersionConversionIsLossless() throws Exception {
+ final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
+ builder.setAutomaticNattKeepaliveTimerEnabled(true);
+ builder.setAutomaticIpVersionSelectionEnabled(true);
+
+ builder.setAuthDigitalSignature(mUserCert, mPrivateKey, mServerRootCa);
+ final Ikev2VpnProfile ikeProfile = builder.build();
+
+ assertEquals(ikeProfile, Ikev2VpnProfile.fromVpnProfile(ikeProfile.toVpnProfile()));
+ }
+
+ @Test
+ public void testAutomaticNattAndIpVersionDefaults() throws Exception {
+ final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
+
+ builder.setAuthDigitalSignature(mUserCert, mPrivateKey, mServerRootCa);
+ final Ikev2VpnProfile ikeProfile = builder.build();
+
+ assertEquals(false, ikeProfile.isAutomaticNattKeepaliveTimerEnabled());
+ assertEquals(false, ikeProfile.isAutomaticIpVersionSelectionEnabled());
+ }
+
+ @Test
public void testEquals() throws Exception {
// Verify building without IkeTunnelConnectionParams
final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
diff --git a/tests/unit/java/com/android/internal/net/VpnProfileTest.java b/tests/unit/java/com/android/internal/net/VpnProfileTest.java
index 0a6d2f2..b2dff2e 100644
--- a/tests/unit/java/com/android/internal/net/VpnProfileTest.java
+++ b/tests/unit/java/com/android/internal/net/VpnProfileTest.java
@@ -20,6 +20,7 @@
import static android.net.cts.util.IkeSessionTestUtils.IKE_PARAMS_V4;
import static com.android.modules.utils.build.SdkLevel.isAtLeastT;
+import static com.android.modules.utils.build.SdkLevel.isAtLeastU;
import static com.android.testutils.ParcelUtils.assertParcelSane;
import static org.junit.Assert.assertEquals;
@@ -55,6 +56,9 @@
private static final int ENCODED_INDEX_RESTRICTED_TO_TEST_NETWORKS = 24;
private static final int ENCODED_INDEX_EXCLUDE_LOCAL_ROUTE = 25;
private static final int ENCODED_INDEX_REQUIRE_PLATFORM_VALIDATION = 26;
+ private static final int ENCODED_INDEX_IKE_TUN_CONN_PARAMS = 27;
+ private static final int ENCODED_INDEX_AUTOMATIC_NATT_KEEPALIVE_TIMER_ENABLED = 28;
+ private static final int ENCODED_INDEX_AUTOMATIC_IP_VERSION_SELECTION_ENABLED = 29;
@Test
public void testDefaults() throws Exception {
@@ -85,12 +89,15 @@
assertFalse(p.isRestrictedToTestNetworks);
assertFalse(p.excludeLocalRoutes);
assertFalse(p.requiresInternetValidation);
+ assertFalse(p.automaticNattKeepaliveTimerEnabled);
+ assertFalse(p.automaticIpVersionSelectionEnabled);
}
private VpnProfile getSampleIkev2Profile(String key) {
final VpnProfile p = new VpnProfile(key, true /* isRestrictedToTestNetworks */,
false /* excludesLocalRoutes */, true /* requiresPlatformValidation */,
- null /* ikeTunConnParams */);
+ null /* ikeTunConnParams */, true /* mAutomaticNattKeepaliveTimerEnabled */,
+ true /* automaticIpVersionSelectionEnabled */);
p.name = "foo";
p.type = VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS;
@@ -128,7 +135,9 @@
private VpnProfile getSampleIkev2ProfileWithIkeTunConnParams(String key) {
final VpnProfile p = new VpnProfile(key, true /* isRestrictedToTestNetworks */,
false /* excludesLocalRoutes */, true /* requiresPlatformValidation */,
- new IkeTunnelConnectionParams(IKE_PARAMS_V4, CHILD_PARAMS));
+ new IkeTunnelConnectionParams(IKE_PARAMS_V4, CHILD_PARAMS),
+ true /* mAutomaticNattKeepaliveTimerEnabled */,
+ true /* automaticIpVersionSelectionEnabled */);
p.name = "foo";
p.server = "bar";
@@ -166,7 +175,11 @@
@Test
public void testParcelUnparcel() {
- if (isAtLeastT()) {
+ if (isAtLeastU()) {
+ // automaticNattKeepaliveTimerEnabled, automaticIpVersionSelectionEnabled added in U.
+ assertParcelSane(getSampleIkev2Profile(DUMMY_PROFILE_KEY), 28);
+ assertParcelSane(getSampleIkev2ProfileWithIkeTunConnParams(DUMMY_PROFILE_KEY), 28);
+ } else if (isAtLeastT()) {
// excludeLocalRoutes, requiresPlatformValidation were added in T.
assertParcelSane(getSampleIkev2Profile(DUMMY_PROFILE_KEY), 26);
assertParcelSane(getSampleIkev2ProfileWithIkeTunConnParams(DUMMY_PROFILE_KEY), 26);
@@ -221,16 +234,28 @@
ENCODED_INDEX_AUTH_PARAMS_INLINE,
ENCODED_INDEX_RESTRICTED_TO_TEST_NETWORKS,
ENCODED_INDEX_EXCLUDE_LOCAL_ROUTE,
- ENCODED_INDEX_REQUIRE_PLATFORM_VALIDATION /* missingIndices */);
+ ENCODED_INDEX_REQUIRE_PLATFORM_VALIDATION,
+ ENCODED_INDEX_IKE_TUN_CONN_PARAMS,
+ ENCODED_INDEX_AUTOMATIC_NATT_KEEPALIVE_TIMER_ENABLED,
+ ENCODED_INDEX_AUTOMATIC_IP_VERSION_SELECTION_ENABLED
+ /* missingIndices */);
assertNull(VpnProfile.decode(DUMMY_PROFILE_KEY, tooFewValues.getBytes()));
}
+ private String getEncodedDecodedIkev2ProfileWithtooFewValues() {
+ return getEncodedDecodedIkev2ProfileMissingValues(
+ ENCODED_INDEX_RESTRICTED_TO_TEST_NETWORKS,
+ ENCODED_INDEX_EXCLUDE_LOCAL_ROUTE,
+ ENCODED_INDEX_REQUIRE_PLATFORM_VALIDATION,
+ ENCODED_INDEX_IKE_TUN_CONN_PARAMS,
+ ENCODED_INDEX_AUTOMATIC_NATT_KEEPALIVE_TIMER_ENABLED,
+ ENCODED_INDEX_AUTOMATIC_IP_VERSION_SELECTION_ENABLED /* missingIndices */);
+ }
+
@Test
public void testEncodeDecodeMissingIsRestrictedToTestNetworks() {
- final String tooFewValues =
- getEncodedDecodedIkev2ProfileMissingValues(
- ENCODED_INDEX_RESTRICTED_TO_TEST_NETWORKS /* missingIndices */);
+ final String tooFewValues = getEncodedDecodedIkev2ProfileWithtooFewValues();
// Verify decoding without isRestrictedToTestNetworks defaults to false
final VpnProfile decoded = VpnProfile.decode(DUMMY_PROFILE_KEY, tooFewValues.getBytes());
@@ -239,10 +264,7 @@
@Test
public void testEncodeDecodeMissingExcludeLocalRoutes() {
- final String tooFewValues =
- getEncodedDecodedIkev2ProfileMissingValues(
- ENCODED_INDEX_EXCLUDE_LOCAL_ROUTE,
- ENCODED_INDEX_REQUIRE_PLATFORM_VALIDATION /* missingIndices */);
+ final String tooFewValues = getEncodedDecodedIkev2ProfileWithtooFewValues();
// Verify decoding without excludeLocalRoutes defaults to false
final VpnProfile decoded = VpnProfile.decode(DUMMY_PROFILE_KEY, tooFewValues.getBytes());
@@ -251,9 +273,7 @@
@Test
public void testEncodeDecodeMissingRequiresValidation() {
- final String tooFewValues =
- getEncodedDecodedIkev2ProfileMissingValues(
- ENCODED_INDEX_REQUIRE_PLATFORM_VALIDATION /* missingIndices */);
+ final String tooFewValues = getEncodedDecodedIkev2ProfileWithtooFewValues();
// Verify decoding without requiresValidation defaults to false
final VpnProfile decoded = VpnProfile.decode(DUMMY_PROFILE_KEY, tooFewValues.getBytes());
@@ -261,6 +281,24 @@
}
@Test
+ public void testEncodeDecodeMissingAutomaticNattKeepaliveTimerEnabled() {
+ final String tooFewValues = getEncodedDecodedIkev2ProfileWithtooFewValues();
+
+ // Verify decoding without automaticNattKeepaliveTimerEnabled defaults to false
+ final VpnProfile decoded = VpnProfile.decode(DUMMY_PROFILE_KEY, tooFewValues.getBytes());
+ assertFalse(decoded.automaticNattKeepaliveTimerEnabled);
+ }
+
+ @Test
+ public void testEncodeDecodeMissingAutomaticIpVersionSelectionEnabled() {
+ final String tooFewValues = getEncodedDecodedIkev2ProfileWithtooFewValues();
+
+ // Verify decoding without automaticIpVersionSelectionEnabled defaults to false
+ final VpnProfile decoded = VpnProfile.decode(DUMMY_PROFILE_KEY, tooFewValues.getBytes());
+ assertFalse(decoded.automaticIpVersionSelectionEnabled);
+ }
+
+ @Test
public void testEncodeDecodeLoginsNotSaved() {
final VpnProfile profile = getSampleIkev2Profile(DUMMY_PROFILE_KEY);
profile.saveLogin = false;
diff --git a/tests/unit/java/com/android/server/BpfNetMapsTest.java b/tests/unit/java/com/android/server/BpfNetMapsTest.java
index 0e17cd7..d189848 100644
--- a/tests/unit/java/com/android/server/BpfNetMapsTest.java
+++ b/tests/unit/java/com/android/server/BpfNetMapsTest.java
@@ -690,6 +690,80 @@
mBpfNetMaps.setUidRule(FIREWALL_CHAIN_DOZABLE, TEST_UID, FIREWALL_RULE_ALLOW));
}
+ private void doTestGetUidRule(final List<Integer> enableChains) throws Exception {
+ mUidOwnerMap.updateEntry(new S32(TEST_UID), new UidOwnerValue(0, getMatch(enableChains)));
+
+ for (final int chain: FIREWALL_CHAINS) {
+ final String testCase = "EnabledChains: " + enableChains + " CheckedChain: " + chain;
+ if (enableChains.contains(chain)) {
+ final int expectedRule = mBpfNetMaps.isFirewallAllowList(chain)
+ ? FIREWALL_RULE_ALLOW : FIREWALL_RULE_DENY;
+ assertEquals(testCase, expectedRule, mBpfNetMaps.getUidRule(chain, TEST_UID));
+ } else {
+ final int expectedRule = mBpfNetMaps.isFirewallAllowList(chain)
+ ? FIREWALL_RULE_DENY : FIREWALL_RULE_ALLOW;
+ assertEquals(testCase, expectedRule, mBpfNetMaps.getUidRule(chain, TEST_UID));
+ }
+ }
+ }
+
+ private void doTestGetUidRule(final int enableChain) throws Exception {
+ doTestGetUidRule(List.of(enableChain));
+ }
+
+ @Test
+ @IgnoreUpTo(Build.VERSION_CODES.S_V2)
+ public void testGetUidRule() throws Exception {
+ doTestGetUidRule(FIREWALL_CHAIN_DOZABLE);
+ doTestGetUidRule(FIREWALL_CHAIN_STANDBY);
+ doTestGetUidRule(FIREWALL_CHAIN_POWERSAVE);
+ doTestGetUidRule(FIREWALL_CHAIN_RESTRICTED);
+ doTestGetUidRule(FIREWALL_CHAIN_LOW_POWER_STANDBY);
+ doTestGetUidRule(FIREWALL_CHAIN_OEM_DENY_1);
+ doTestGetUidRule(FIREWALL_CHAIN_OEM_DENY_2);
+ doTestGetUidRule(FIREWALL_CHAIN_OEM_DENY_3);
+ }
+
+ @Test
+ @IgnoreUpTo(Build.VERSION_CODES.S_V2)
+ public void testGetUidRuleMultipleChainEnabled() throws Exception {
+ doTestGetUidRule(List.of(
+ FIREWALL_CHAIN_DOZABLE,
+ FIREWALL_CHAIN_STANDBY));
+ doTestGetUidRule(List.of(
+ FIREWALL_CHAIN_DOZABLE,
+ FIREWALL_CHAIN_STANDBY,
+ FIREWALL_CHAIN_POWERSAVE,
+ FIREWALL_CHAIN_RESTRICTED));
+ doTestGetUidRule(FIREWALL_CHAINS);
+ }
+
+ @Test
+ @IgnoreUpTo(Build.VERSION_CODES.S_V2)
+ public void testGetUidRuleNoEntry() throws Exception {
+ mUidOwnerMap.clear();
+ for (final int chain: FIREWALL_CHAINS) {
+ final int expectedRule = mBpfNetMaps.isFirewallAllowList(chain)
+ ? FIREWALL_RULE_DENY : FIREWALL_RULE_ALLOW;
+ assertEquals(expectedRule, mBpfNetMaps.getUidRule(chain, TEST_UID));
+ }
+ }
+
+ @Test
+ @IgnoreUpTo(Build.VERSION_CODES.S_V2)
+ public void testGetUidRuleInvalidChain() {
+ final Class<ServiceSpecificException> expected = ServiceSpecificException.class;
+ assertThrows(expected, () -> mBpfNetMaps.getUidRule(-1 /* childChain */, TEST_UID));
+ assertThrows(expected, () -> mBpfNetMaps.getUidRule(1000 /* childChain */, TEST_UID));
+ }
+
+ @Test
+ @IgnoreAfter(Build.VERSION_CODES.S_V2)
+ public void testGetUidRuleBeforeT() {
+ assertThrows(UnsupportedOperationException.class,
+ () -> mBpfNetMaps.getUidRule(FIREWALL_CHAIN_DOZABLE, TEST_UID));
+ }
+
@Test
@IgnoreUpTo(Build.VERSION_CODES.S_V2)
public void testReplaceUidChain() throws Exception {
diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
index 634d5c9..ea50999 100755
--- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -27,6 +27,7 @@
import static android.Manifest.permission.MANAGE_TEST_NETWORKS;
import static android.Manifest.permission.NETWORK_FACTORY;
import static android.Manifest.permission.NETWORK_SETTINGS;
+import static android.Manifest.permission.NETWORK_SETUP_WIZARD;
import static android.Manifest.permission.NETWORK_STACK;
import static android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD;
import static android.app.PendingIntent.FLAG_IMMUTABLE;
@@ -5320,6 +5321,13 @@
callback.expectAvailableCallbacksUnvalidated(mCellAgent);
mCm.unregisterNetworkCallback(callback);
+ mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_DENIED);
+ mServiceContext.setPermission(NETWORK_SETUP_WIZARD, PERMISSION_GRANTED);
+ mCm.registerSystemDefaultNetworkCallback(callback, handler);
+ callback.expectAvailableCallbacksUnvalidated(mCellAgent);
+ mCm.unregisterNetworkCallback(callback);
+
+ mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
mCm.registerDefaultNetworkCallbackForUid(APP1_UID, callback, handler);
callback.expectAvailableCallbacksUnvalidated(mCellAgent);
mCm.unregisterNetworkCallback(callback);